add deps
This commit is contained in:
parent
8a699044be
commit
4267ac8731
|
@ -0,0 +1,17 @@
|
|||
xversion.go
|
||||
zversion.go
|
||||
|
||||
# ---> Go
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Test binary, build with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
|
@ -0,0 +1,312 @@
|
|||
Mozilla Public License Version 2.0
|
||||
|
||||
1. Definitions
|
||||
|
||||
1.1. "Contributor" means each individual or legal entity that creates, contributes
|
||||
to the creation of, or owns Covered Software.
|
||||
|
||||
1.2. "Contributor Version" means the combination of the Contributions of others
|
||||
(if any) used by a Contributor and that particular Contributor's Contribution.
|
||||
|
||||
1.3. "Contribution" means Covered Software of a particular Contributor.
|
||||
|
||||
1.4. "Covered Software" means Source Code Form to which the initial Contributor
|
||||
has attached the notice in Exhibit A, the Executable Form of such Source Code
|
||||
Form, and Modifications of such Source Code Form, in each case including portions
|
||||
thereof.
|
||||
|
||||
1.5. "Incompatible With Secondary Licenses" means
|
||||
|
||||
(a) that the initial Contributor has attached the notice described in Exhibit
|
||||
B to the Covered Software; or
|
||||
|
||||
(b) that the Covered Software was made available under the terms of version
|
||||
1.1 or earlier of the License, but not also under the terms of a Secondary
|
||||
License.
|
||||
|
||||
1.6. "Executable Form" means any form of the work other than Source Code Form.
|
||||
|
||||
1.7. "Larger Work" means a work that combines Covered Software with other
|
||||
material, in a separate file or files, that is not Covered Software.
|
||||
|
||||
1.8. "License" means this document.
|
||||
|
||||
1.9. "Licensable" means having the right to grant, to the maximum extent possible,
|
||||
whether at the time of the initial grant or subsequently, any and all of the
|
||||
rights conveyed by this License.
|
||||
|
||||
1.10. "Modifications" means any of the following:
|
||||
|
||||
(a) any file in Source Code Form that results from an addition to, deletion
|
||||
from, or modification of the contents of Covered Software; or
|
||||
|
||||
(b) any new file in Source Code Form that contains any Covered Software.
|
||||
|
||||
1.11. "Patent Claims" of a Contributor means any patent claim(s), including
|
||||
without limitation, method, process, and apparatus claims, in any patent Licensable
|
||||
by such Contributor that would be infringed, but for the grant of the License,
|
||||
by the making, using, selling, offering for sale, having made, import, or
|
||||
transfer of either its Contributions or its Contributor Version.
|
||||
|
||||
1.12. "Secondary License" means either the GNU General Public License, Version
|
||||
2.0, the GNU Lesser General Public License, Version 2.1, the GNU Affero General
|
||||
Public License, Version 3.0, or any later versions of those licenses.
|
||||
|
||||
1.13. "Source Code Form" means the form of the work preferred for making modifications.
|
||||
|
||||
1.14. "You" (or "Your") means an individual or a legal entity exercising rights
|
||||
under this License. For legal entities, "You" includes any entity that controls,
|
||||
is controlled by, or is under common control with You. For purposes of this
|
||||
definition, "control" means (a) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or otherwise,
|
||||
or (b) ownership of more than fifty percent (50%) of the outstanding shares
|
||||
or beneficial ownership of such entity.
|
||||
|
||||
2. License Grants and Conditions
|
||||
|
||||
2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive
|
||||
license:
|
||||
|
||||
(a) under intellectual property rights (other than patent or trademark) Licensable
|
||||
by such Contributor to use, reproduce, make available, modify, display, perform,
|
||||
distribute, and otherwise exploit its Contributions, either on an unmodified
|
||||
basis, with Modifications, or as part of a Larger Work; and
|
||||
|
||||
(b) under Patent Claims of such Contributor to make, use, sell, offer for
|
||||
sale, have made, import, and otherwise transfer either its Contributions or
|
||||
its Contributor Version.
|
||||
|
||||
2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution become
|
||||
effective for each Contribution on the date the Contributor first distributes
|
||||
such Contribution.
|
||||
|
||||
2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under this
|
||||
License. No additional rights or licenses will be implied from the distribution
|
||||
or licensing of Covered Software under this License. Notwithstanding Section
|
||||
2.1(b) above, no patent license is granted by a Contributor:
|
||||
|
||||
(a) for any code that a Contributor has removed from Covered Software; or
|
||||
|
||||
(b) for infringements caused by: (i) Your and any other third party's modifications
|
||||
of Covered Software, or (ii) the combination of its Contributions with other
|
||||
software (except as part of its Contributor Version); or
|
||||
|
||||
(c) under Patent Claims infringed by Covered Software in the absence of its
|
||||
Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks, or
|
||||
logos of any Contributor (except as may be necessary to comply with the notice
|
||||
requirements in Section 3.4).
|
||||
|
||||
2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to distribute
|
||||
the Covered Software under a subsequent version of this License (see Section
|
||||
10.2) or under the terms of a Secondary License (if permitted under the terms
|
||||
of Section 3.3).
|
||||
|
||||
2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its Contributions
|
||||
are its original creation(s) or it has sufficient rights to grant the rights
|
||||
to its Contributions conveyed by this License.
|
||||
|
||||
2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under applicable
|
||||
copyright doctrines of fair use, fair dealing, or other equivalents.
|
||||
|
||||
2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
|
||||
Section 2.1.
|
||||
|
||||
3. Responsibilities
|
||||
|
||||
3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any Modifications
|
||||
that You create or to which You contribute, must be under the terms of this
|
||||
License. You must inform recipients that the Source Code Form of the Covered
|
||||
Software is governed by the terms of this License, and how they can obtain
|
||||
a copy of this License. You may not attempt to alter or restrict the recipients'
|
||||
rights in the Source Code Form.
|
||||
|
||||
3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
(a) such Covered Software must also be made available in Source Code Form,
|
||||
as described in Section 3.1, and You must inform recipients of the Executable
|
||||
Form how they can obtain a copy of such Source Code Form by reasonable means
|
||||
in a timely manner, at a charge no more than the cost of distribution to the
|
||||
recipient; and
|
||||
|
||||
(b) You may distribute such Executable Form under the terms of this License,
|
||||
or sublicense it under different terms, provided that the license for the
|
||||
Executable Form does not attempt to limit or alter the recipients' rights
|
||||
in the Source Code Form under this License.
|
||||
|
||||
3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice, provided
|
||||
that You also comply with the requirements of this License for the Covered
|
||||
Software. If the Larger Work is a combination of Covered Software with a work
|
||||
governed by one or more Secondary Licenses, and the Covered Software is not
|
||||
Incompatible With Secondary Licenses, this License permits You to additionally
|
||||
distribute such Covered Software under the terms of such Secondary License(s),
|
||||
so that the recipient of the Larger Work may, at their option, further distribute
|
||||
the Covered Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
|
||||
3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices (including
|
||||
copyright notices, patent notices, disclaimers of warranty, or limitations
|
||||
of liability) contained within the Source Code Form of the Covered Software,
|
||||
except that You may alter any license notices to the extent required to remedy
|
||||
known factual inaccuracies.
|
||||
|
||||
3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support, indemnity
|
||||
or liability obligations to one or more recipients of Covered Software. However,
|
||||
You may do so only on Your own behalf, and not on behalf of any Contributor.
|
||||
You must make it absolutely clear that any such warranty, support, indemnity,
|
||||
or liability obligation is offered by You alone, and You hereby agree to indemnify
|
||||
every Contributor for any liability incurred by such Contributor as a result
|
||||
of warranty, support, indemnity or liability terms You offer. You may include
|
||||
additional disclaimers of warranty and limitations of liability specific to
|
||||
any jurisdiction.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this License
|
||||
with respect to some or all of the Covered Software due to statute, judicial
|
||||
order, or regulation then You must: (a) comply with the terms of this License
|
||||
to the maximum extent possible; and (b) describe the limitations and the code
|
||||
they affect. Such description must be placed in a text file included with
|
||||
all distributions of the Covered Software under this License. Except to the
|
||||
extent prohibited by statute or regulation, such description must be sufficiently
|
||||
detailed for a recipient of ordinary skill to be able to understand it.
|
||||
|
||||
5. Termination
|
||||
|
||||
5.1. The rights granted under this License will terminate automatically if
|
||||
You fail to comply with any of its terms. However, if You become compliant,
|
||||
then the rights granted under this License from a particular Contributor are
|
||||
reinstated (a) provisionally, unless and until such Contributor explicitly
|
||||
and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor
|
||||
fails to notify You of the non-compliance by some reasonable means prior to
|
||||
60 days after You have come back into compliance. Moreover, Your grants from
|
||||
a particular Contributor are reinstated on an ongoing basis if such Contributor
|
||||
notifies You of the non-compliance by some reasonable means, this is the first
|
||||
time You have received notice of non-compliance with this License from such
|
||||
Contributor, and You become compliant prior to 30 days after Your receipt
|
||||
of the notice.
|
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent infringement
|
||||
claim (excluding declaratory judgment actions, counter-claims, and cross-claims)
|
||||
alleging that a Contributor Version directly or indirectly infringes any patent,
|
||||
then the rights granted to You by any and all Contributors for the Covered
|
||||
Software under Section 2.1 of this License shall terminate.
|
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all end
|
||||
user license agreements (excluding distributors and resellers) which have
|
||||
been validly granted by You or Your distributors under this License prior
|
||||
to termination shall survive termination.
|
||||
|
||||
6. Disclaimer of Warranty
|
||||
|
||||
Covered Software is provided under this License on an "as is" basis, without
|
||||
warranty of any kind, either expressed, implied, or statutory, including,
|
||||
without limitation, warranties that the Covered Software is free of defects,
|
||||
merchantable, fit for a particular purpose or non-infringing. The entire risk
|
||||
as to the quality and performance of the Covered Software is with You. Should
|
||||
any Covered Software prove defective in any respect, You (not any Contributor)
|
||||
assume the cost of any necessary servicing, repair, or correction. This disclaimer
|
||||
of warranty constitutes an essential part of this License. No use of any Covered
|
||||
Software is authorized under this License except under this disclaimer.
|
||||
|
||||
7. Limitation of Liability
|
||||
|
||||
Under no circumstances and under no legal theory, whether tort (including
|
||||
negligence), contract, or otherwise, shall any Contributor, or anyone who
|
||||
distributes Covered Software as permitted above, be liable to You for any
|
||||
direct, indirect, special, incidental, or consequential damages of any character
|
||||
including, without limitation, damages for lost profits, loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all other commercial
|
||||
damages or losses, even if such party shall have been informed of the possibility
|
||||
of such damages. This limitation of liability shall not apply to liability
|
||||
for death or personal injury resulting from such party's negligence to the
|
||||
extent applicable law prohibits such limitation. Some jurisdictions do not
|
||||
allow the exclusion or limitation of incidental or consequential damages,
|
||||
so this exclusion and limitation may not apply to You.
|
||||
|
||||
8. Litigation
|
||||
|
||||
Any litigation relating to this License may be brought only in the courts
|
||||
of a jurisdiction where the defendant maintains its principal place of business
|
||||
and such litigation shall be governed by laws of that jurisdiction, without
|
||||
reference to its conflict-of-law provisions. Nothing in this Section shall
|
||||
prevent a party's ability to bring cross-claims or counter-claims.
|
||||
|
||||
9. Miscellaneous
|
||||
|
||||
This License represents the complete agreement concerning the subject matter
|
||||
hereof. If any provision of this License is held to be unenforceable, such
|
||||
provision shall be reformed only to the extent necessary to make it enforceable.
|
||||
Any law or regulation which provides that the language of a contract shall
|
||||
be construed against the drafter shall not be used to construe this License
|
||||
against a Contributor.
|
||||
|
||||
10. Versions of the License
|
||||
|
||||
10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section 10.3,
|
||||
no one other than the license steward has the right to modify or publish new
|
||||
versions of this License. Each version will be given a distinguishing version
|
||||
number.
|
||||
|
||||
10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version of
|
||||
the License under which You originally received the Covered Software, or under
|
||||
the terms of any subsequent version published by the license steward.
|
||||
|
||||
10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to create
|
||||
a new license for such software, you may create and use a modified version
|
||||
of this License if you rename the license and remove any references to the
|
||||
name of the license steward (except to note that such modified license differs
|
||||
from this License).
|
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses
|
||||
|
||||
If You choose to distribute Source Code Form that is Incompatible With Secondary
|
||||
Licenses under the terms of this version of the License, the notice described
|
||||
in Exhibit B of this License must be attached. Exhibit A - Source Code Form
|
||||
License Notice
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License,
|
||||
v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain
|
||||
one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular file,
|
||||
then You may include the notice in a location (such as a LICENSE file in a
|
||||
relevant directory) where a recipient would be likely to look for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||
|
||||
This Source Code Form is "Incompatible With Secondary Licenses", as defined
|
||||
by the Mozilla Public License, v. 2.0.
|
|
@ -0,0 +1,195 @@
|
|||
# git-version.go
|
||||
|
||||
Use git tags to add semver to your go package.
|
||||
|
||||
```txt
|
||||
Goal: Either use an exact version like v1.0.0
|
||||
or translate the git version like v1.0.0-4-g0000000
|
||||
to a semver like v1.0.1-pre4+g0000000
|
||||
|
||||
Fail gracefully when git repo isn't available.
|
||||
```
|
||||
|
||||
# Demo
|
||||
|
||||
Generate an `xversion.go` file:
|
||||
|
||||
```bash
|
||||
go run git.rootprojects.org/root/go-gitver
|
||||
cat xversion.go
|
||||
```
|
||||
|
||||
<small>**Note**: The file is named `xversion.go` by default so that the
|
||||
generated file's `init()` will come later, and thus take priority, over
|
||||
most other files.</small>
|
||||
|
||||
See `go-gitver`s self-generated version:
|
||||
|
||||
```bash
|
||||
go run git.rootprojects.org/root/go-gitver version
|
||||
```
|
||||
|
||||
# QuickStart
|
||||
|
||||
Add this to the top of your main file:
|
||||
|
||||
```go
|
||||
//go:generate go run -mod=vendor git.rootprojects.org/root/go-gitver
|
||||
|
||||
```
|
||||
|
||||
Add a file that imports go-gitver (for versioning)
|
||||
|
||||
```go
|
||||
// +build tools
|
||||
|
||||
package example
|
||||
|
||||
import _ "git.rootprojects.org/root/go-gitver"
|
||||
```
|
||||
|
||||
Change you build instructions to be something like this:
|
||||
|
||||
```bash
|
||||
go mod vendor
|
||||
go generate -mod=vendor ./...
|
||||
go build -mod=vendor -o example cmd/example/*.go
|
||||
```
|
||||
|
||||
You don't have to use `mod vendor`, but I highly recommend it.
|
||||
|
||||
# Options
|
||||
|
||||
```txt
|
||||
version print version and exit
|
||||
--fail exit with non-zero status code on failure
|
||||
--package <name> will set the package name
|
||||
--outfile <name> will replace `xversion.go` with the given file path
|
||||
```
|
||||
|
||||
ENVs
|
||||
|
||||
```bash
|
||||
# Alias for --fail
|
||||
GITVER_FAIL=true
|
||||
```
|
||||
|
||||
For example:
|
||||
|
||||
```go
|
||||
//go:generate go run -mod=vendor git.rootprojects.org/root/go-gitver --fail
|
||||
|
||||
```
|
||||
|
||||
```bash
|
||||
go run -mod=vendor git.rootprojects.org/root/go-gitver version
|
||||
```
|
||||
|
||||
# Usage
|
||||
|
||||
See `examples/basic`
|
||||
|
||||
1. Create a `tools` package in your project
|
||||
2. Guard it against regular builds with `// +build tools`
|
||||
3. Include `_ "git.rootprojects.org/root/go-gitver"` in the imports
|
||||
4. Declare `var GitRev, GitVersion, GitTimestamp string` in your `package main`
|
||||
5. Include `//go:generate go run -mod=vendor git.rootprojects.org/root/go-gitver` as well
|
||||
|
||||
`tools/tools.go`:
|
||||
|
||||
```go
|
||||
// +build tools
|
||||
|
||||
// This is a dummy package for build tooling
|
||||
package tools
|
||||
|
||||
import (
|
||||
_ "git.rootprojects.org/root/go-gitver"
|
||||
)
|
||||
```
|
||||
|
||||
`main.go`:
|
||||
|
||||
```go
|
||||
//go:generate go run git.rootprojects.org/root/go-gitver --fail
|
||||
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
var (
|
||||
GitRev = "0000000"
|
||||
GitVersion = "v0.0.0-pre0+0000000"
|
||||
GitTimestamp = "0000-00-00T00:00:00+0000"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(GitRev)
|
||||
fmt.Println(GitVersion)
|
||||
fmt.Println(GitTimestamp)
|
||||
}
|
||||
```
|
||||
|
||||
If you're using `go mod vendor` (which I highly recommend that you do),
|
||||
you'd modify the `go:generate` ever so slightly:
|
||||
|
||||
```go
|
||||
//go:generate go run -mod=vendor git.rootprojects.org/root/go-gitver --fail
|
||||
```
|
||||
|
||||
The only reason I didn't do that in the example is that I'd be included
|
||||
the repository in itself and that would be... weird.
|
||||
|
||||
# Why a tools package?
|
||||
|
||||
> import "git.rootprojects.org/root/go-gitver" is a program, not an importable package
|
||||
|
||||
Having a tools package with a build tag that you don't use is a nice way to add exact
|
||||
versions of a command package used for tooling to your `go.mod` with `go mod tidy`,
|
||||
without getting the error above.
|
||||
|
||||
# git: behind the curtain
|
||||
|
||||
These are the commands that are used under the hood to produce the versions.
|
||||
|
||||
Shows the git tag + description. Assumes that you're using the semver format `v1.0.0` for your base tags.
|
||||
|
||||
```bash
|
||||
git describe --tags --dirty --always
|
||||
# v1.0.0
|
||||
# v1.0.0-1-g0000000
|
||||
# v1.0.0-dirty
|
||||
```
|
||||
|
||||
Show the commit date (when the commit made it into the current tree).
|
||||
Internally we use the current date when the working tree is dirty.
|
||||
|
||||
```bash
|
||||
git show v1.0.0-1-g0000000 --format=%cd --date=format:%Y-%m-%dT%H:%M:%SZ%z --no-patch
|
||||
# 2010-01-01T20:30:00Z-0600
|
||||
# fatal: ambiguous argument 'v1.0.0-1-g0000000-dirty': unknown revision or path not in the working tree.
|
||||
```
|
||||
|
||||
Shows the most recent commit.
|
||||
|
||||
```bash
|
||||
git rev-parse HEAD
|
||||
# 0000000000000000000000000000000000000000
|
||||
```
|
||||
|
||||
# Errors
|
||||
|
||||
### cannot find package "."
|
||||
|
||||
```txt
|
||||
package git.rootprojects.org/root/go-gitver: cannot find package "." in:
|
||||
/Users/me/go-example/vendor/git.rootprojects.org/root/go-gitver
|
||||
cmd/example/example.go:1: running "go": exit status 1
|
||||
```
|
||||
|
||||
You forgot to update deps and re-vendor:
|
||||
|
||||
```bash
|
||||
go mod tidy
|
||||
go mod vendor
|
||||
```
|
|
@ -0,0 +1,104 @@
|
|||
//go:generate go run -mod=vendor git.rootprojects.org/root/go-gitver
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"go/format"
|
||||
"os"
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
"git.rootprojects.org/root/go-gitver/gitver"
|
||||
)
|
||||
|
||||
var GitRev, GitVersion, GitTimestamp string
|
||||
var exitCode int
|
||||
var verFile = "xversion.go"
|
||||
|
||||
func main() {
|
||||
pkg := "main"
|
||||
|
||||
args := os.Args[1:]
|
||||
for i := range args {
|
||||
arg := args[i]
|
||||
if "-f" == arg || "--fail" == arg {
|
||||
exitCode = 1
|
||||
} else if ("--outfile" == arg || "-o" == arg) && len(args) > i+1 {
|
||||
verFile = args[i+1]
|
||||
args[i+1] = ""
|
||||
} else if "--package" == arg && len(args) > i+1 {
|
||||
pkg = args[i+1]
|
||||
args[i+1] = ""
|
||||
} else if "-V" == arg || "version" == arg || "-version" == arg || "--version" == arg {
|
||||
fmt.Println(GitRev)
|
||||
fmt.Println(GitVersion)
|
||||
fmt.Println(GitTimestamp)
|
||||
os.Exit(0)
|
||||
}
|
||||
}
|
||||
if "" != os.Getenv("GITVER_FAIL") && "false" != os.Getenv("GITVER_FAIL") {
|
||||
exitCode = 1
|
||||
}
|
||||
|
||||
v, err := gitver.ExecAndParse()
|
||||
if nil != err {
|
||||
fmt.Fprintf(os.Stderr, "Failed to get git version: %s\n", err)
|
||||
if exitCode > 0 {
|
||||
os.Exit(exitCode)
|
||||
}
|
||||
v = &gitver.Versions{
|
||||
Timestamp: time.Now(),
|
||||
}
|
||||
}
|
||||
|
||||
// Create or overwrite the go file from template
|
||||
var buf bytes.Buffer
|
||||
if err := versionTpl.Execute(&buf, struct {
|
||||
Package string
|
||||
Timestamp string
|
||||
Version string
|
||||
GitRev string
|
||||
}{
|
||||
Package: pkg,
|
||||
Timestamp: v.Timestamp.Format(time.RFC3339),
|
||||
Version: v.Version,
|
||||
GitRev: v.Rev,
|
||||
}); nil != err {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Format
|
||||
src, err := format.Source(buf.Bytes())
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Write to disk (in the Current Working Directory)
|
||||
f, err := os.Create(verFile)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
if _, err := f.Write(src); nil != err {
|
||||
panic(err)
|
||||
}
|
||||
if err := f.Close(); nil != err {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var versionTpl = template.Must(template.New("").Parse(`// Code generated by go generate; DO NOT EDIT.
|
||||
package {{ .Package }}
|
||||
|
||||
func init() {
|
||||
{{ if .GitRev -}}
|
||||
GitRev = "{{ .GitRev }}"
|
||||
{{ end -}}
|
||||
{{ if .Version -}}
|
||||
GitVersion = "{{ .Version }}"
|
||||
{{ end -}}
|
||||
GitTimestamp = "{{ .Timestamp }}"
|
||||
}
|
||||
`))
|
|
@ -0,0 +1,143 @@
|
|||
package gitver
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var exactVer *regexp.Regexp
|
||||
var gitVer *regexp.Regexp
|
||||
|
||||
func init() {
|
||||
// exactly vX.Y.Z (go-compatible semver)
|
||||
exactVer = regexp.MustCompile(`^v\d+\.\d+\.\d+$`)
|
||||
|
||||
// vX.Y.Z-n-g0000000 git post-release, semver prerelease
|
||||
// vX.Y.Z-dirty git post-release, semver prerelease
|
||||
gitVer = regexp.MustCompile(`^(v\d+\.\d+)\.(\d+)(-(\d+))?(-(g[0-9a-f]+))?(-(dirty))?`)
|
||||
}
|
||||
|
||||
type Versions struct {
|
||||
Timestamp time.Time
|
||||
Version string
|
||||
Rev string
|
||||
}
|
||||
|
||||
func ExecAndParse() (*Versions, error) {
|
||||
desc, err := gitDesc()
|
||||
if nil != err {
|
||||
return nil, err
|
||||
}
|
||||
rev, err := gitRev()
|
||||
if nil != err {
|
||||
return nil, err
|
||||
}
|
||||
ver, err := semVer(desc)
|
||||
if nil != err {
|
||||
return nil, err
|
||||
}
|
||||
ts, err := gitTimestamp(desc)
|
||||
if nil != err {
|
||||
ts = time.Now()
|
||||
}
|
||||
|
||||
return &Versions{
|
||||
Timestamp: ts,
|
||||
Version: ver,
|
||||
Rev: rev,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func gitDesc() (string, error) {
|
||||
args := strings.Split("git describe --tags --dirty --always", " ")
|
||||
cmd := exec.Command(args[0], args[1:]...)
|
||||
out, err := cmd.CombinedOutput()
|
||||
if nil != err {
|
||||
// Don't panic, just carry on
|
||||
//out = []byte("v0.0.0-0-g0000000")
|
||||
return "", err
|
||||
}
|
||||
return strings.TrimSpace(string(out)), nil
|
||||
}
|
||||
|
||||
func gitRev() (string, error) {
|
||||
args := strings.Split("git rev-parse HEAD", " ")
|
||||
cmd := exec.Command(args[0], args[1:]...)
|
||||
out, err := cmd.CombinedOutput()
|
||||
if nil != err {
|
||||
return "", fmt.Errorf("\nUnexpected Error\n\n"+
|
||||
"Please open an issue at https://git.rootprojects.org/root/go-gitver/issues/new \n"+
|
||||
"Please include the following:\n\n"+
|
||||
"Command: %s\n"+
|
||||
"Output: %s\n"+
|
||||
"Error: %s\n"+
|
||||
"\nPlease and Thank You.\n\n", strings.Join(args, " "), out, err)
|
||||
}
|
||||
return strings.TrimSpace(string(out)), nil
|
||||
}
|
||||
|
||||
func semVer(desc string) (string, error) {
|
||||
if exactVer.MatchString(desc) {
|
||||
// v1.0.0
|
||||
return desc, nil
|
||||
}
|
||||
|
||||
if !gitVer.MatchString(desc) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// (v1.0).(0)(-(1))(-(g0000000))(-(dirty))
|
||||
vers := gitVer.FindStringSubmatch(desc)
|
||||
patch, err := strconv.Atoi(vers[2])
|
||||
if nil != err {
|
||||
return "", fmt.Errorf("\nUnexpected Error\n\n"+
|
||||
"Please open an issue at https://git.rootprojects.org/root/go-gitver/issues/new \n"+
|
||||
"Please include the following:\n\n"+
|
||||
"git description: %s\n"+
|
||||
"RegExp: %#v\n"+
|
||||
"Error: %s\n"+
|
||||
"\nPlease and Thank You.\n\n", desc, gitVer, err)
|
||||
}
|
||||
|
||||
// v1.0.1-pre1
|
||||
// v1.0.1-pre1+g0000000
|
||||
// v1.0.1-pre0+dirty
|
||||
// v1.0.1-pre0+g0000000-dirty
|
||||
if "" == vers[4] {
|
||||
vers[4] = "0"
|
||||
}
|
||||
ver := fmt.Sprintf("%s.%d-pre%s", vers[1], patch+1, vers[4])
|
||||
if "" != vers[6] || "dirty" == vers[8] {
|
||||
ver += "+"
|
||||
if "" != vers[6] {
|
||||
ver += vers[6]
|
||||
if "" != vers[8] {
|
||||
ver += "-"
|
||||
}
|
||||
}
|
||||
ver += vers[8]
|
||||
}
|
||||
|
||||
return ver, nil
|
||||
}
|
||||
|
||||
func gitTimestamp(desc string) (time.Time, error) {
|
||||
args := []string{
|
||||
"git",
|
||||
"show", desc,
|
||||
"--format=%cd",
|
||||
"--date=format:%Y-%m-%dT%H:%M:%SZ%z",
|
||||
"--no-patch",
|
||||
}
|
||||
cmd := exec.Command(args[0], args[1:]...)
|
||||
out, err := cmd.CombinedOutput()
|
||||
if nil != err {
|
||||
// a dirty desc was probably used
|
||||
return time.Time{}, err
|
||||
}
|
||||
return time.Parse(time.RFC3339, strings.TrimSpace(string(out)))
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
module git.rootprojects.org/root/go-gitver
|
||||
|
||||
go 1.12
|
|
@ -0,0 +1,9 @@
|
|||
package main
|
||||
|
||||
// use recently generated version info as a fallback
|
||||
// for when git isn't present (i.e. go run <url>)
|
||||
func init() {
|
||||
GitRev = "0921ed1e6007493c886c87ee9a15f2cceecb1f9f"
|
||||
GitVersion = "v1.1.2"
|
||||
GitTimestamp = "2019-07-01T02:32:58-06:00"
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
# This source code refers to The Go Authors for copyright purposes.
|
||||
# The master list of authors is in the main Go distribution,
|
||||
# visible at http://tip.golang.org/AUTHORS.
|
|
@ -0,0 +1,3 @@
|
|||
# This source code was written by the Go contributors.
|
||||
# The master list of contributors is in the main Go distribution,
|
||||
# visible at http://tip.golang.org/CONTRIBUTORS.
|
|
@ -0,0 +1,27 @@
|
|||
Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,22 @@
|
|||
Additional IP Rights Grant (Patents)
|
||||
|
||||
"This implementation" means the copyrightable works distributed by
|
||||
Google as part of the Go project.
|
||||
|
||||
Google hereby grants to You a perpetual, worldwide, non-exclusive,
|
||||
no-charge, royalty-free, irrevocable (except as stated in this section)
|
||||
patent license to make, have made, use, offer to sell, sell, import,
|
||||
transfer and otherwise run, modify and propagate the contents of this
|
||||
implementation of Go, where such license applies only to those patent
|
||||
claims, both currently owned or controlled by Google and acquired in
|
||||
the future, licensable by Google that are necessarily infringed by this
|
||||
implementation of Go. This grant does not include claims that would be
|
||||
infringed only as a consequence of further modification of this
|
||||
implementation. If you or your agent or exclusive licensee institute or
|
||||
order or agree to the institution of patent litigation against any
|
||||
entity (including a cross-claim or counterclaim in a lawsuit) alleging
|
||||
that this implementation of Go or any code incorporated within this
|
||||
implementation of Go constitutes direct or contributory patent
|
||||
infringement, or inducement of patent infringement, then any patent
|
||||
rights granted to you under this License for this implementation of Go
|
||||
shall terminate as of the date such litigation is filed.
|
|
@ -0,0 +1,13 @@
|
|||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build windows
|
||||
// +build go1.9
|
||||
|
||||
package windows
|
||||
|
||||
import "syscall"
|
||||
|
||||
type Errno = syscall.Errno
|
||||
type SysProcAttr = syscall.SysProcAttr
|
|
@ -0,0 +1,13 @@
|
|||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//
|
||||
// System calls for 386, Windows are implemented in runtime/syscall_windows.goc
|
||||
//
|
||||
|
||||
TEXT ·getprocaddress(SB), 7, $0-16
|
||||
JMP syscall·getprocaddress(SB)
|
||||
|
||||
TEXT ·loadlibrary(SB), 7, $0-12
|
||||
JMP syscall·loadlibrary(SB)
|
|
@ -0,0 +1,13 @@
|
|||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//
|
||||
// System calls for amd64, Windows are implemented in runtime/syscall_windows.goc
|
||||
//
|
||||
|
||||
TEXT ·getprocaddress(SB), 7, $0-32
|
||||
JMP syscall·getprocaddress(SB)
|
||||
|
||||
TEXT ·loadlibrary(SB), 7, $0-24
|
||||
JMP syscall·loadlibrary(SB)
|
|
@ -0,0 +1,11 @@
|
|||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
TEXT ·getprocaddress(SB),NOSPLIT,$0
|
||||
B syscall·getprocaddress(SB)
|
||||
|
||||
TEXT ·loadlibrary(SB),NOSPLIT,$0
|
||||
B syscall·loadlibrary(SB)
|
|
@ -0,0 +1,378 @@
|
|||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package windows
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// DLLError describes reasons for DLL load failures.
|
||||
type DLLError struct {
|
||||
Err error
|
||||
ObjName string
|
||||
Msg string
|
||||
}
|
||||
|
||||
func (e *DLLError) Error() string { return e.Msg }
|
||||
|
||||
// Implemented in runtime/syscall_windows.goc; we provide jumps to them in our assembly file.
|
||||
func loadlibrary(filename *uint16) (handle uintptr, err syscall.Errno)
|
||||
func getprocaddress(handle uintptr, procname *uint8) (proc uintptr, err syscall.Errno)
|
||||
|
||||
// A DLL implements access to a single DLL.
|
||||
type DLL struct {
|
||||
Name string
|
||||
Handle Handle
|
||||
}
|
||||
|
||||
// LoadDLL loads DLL file into memory.
|
||||
//
|
||||
// Warning: using LoadDLL without an absolute path name is subject to
|
||||
// DLL preloading attacks. To safely load a system DLL, use LazyDLL
|
||||
// with System set to true, or use LoadLibraryEx directly.
|
||||
func LoadDLL(name string) (dll *DLL, err error) {
|
||||
namep, err := UTF16PtrFromString(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
h, e := loadlibrary(namep)
|
||||
if e != 0 {
|
||||
return nil, &DLLError{
|
||||
Err: e,
|
||||
ObjName: name,
|
||||
Msg: "Failed to load " + name + ": " + e.Error(),
|
||||
}
|
||||
}
|
||||
d := &DLL{
|
||||
Name: name,
|
||||
Handle: Handle(h),
|
||||
}
|
||||
return d, nil
|
||||
}
|
||||
|
||||
// MustLoadDLL is like LoadDLL but panics if load operation failes.
|
||||
func MustLoadDLL(name string) *DLL {
|
||||
d, e := LoadDLL(name)
|
||||
if e != nil {
|
||||
panic(e)
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
// FindProc searches DLL d for procedure named name and returns *Proc
|
||||
// if found. It returns an error if search fails.
|
||||
func (d *DLL) FindProc(name string) (proc *Proc, err error) {
|
||||
namep, err := BytePtrFromString(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
a, e := getprocaddress(uintptr(d.Handle), namep)
|
||||
if e != 0 {
|
||||
return nil, &DLLError{
|
||||
Err: e,
|
||||
ObjName: name,
|
||||
Msg: "Failed to find " + name + " procedure in " + d.Name + ": " + e.Error(),
|
||||
}
|
||||
}
|
||||
p := &Proc{
|
||||
Dll: d,
|
||||
Name: name,
|
||||
addr: a,
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// MustFindProc is like FindProc but panics if search fails.
|
||||
func (d *DLL) MustFindProc(name string) *Proc {
|
||||
p, e := d.FindProc(name)
|
||||
if e != nil {
|
||||
panic(e)
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
// Release unloads DLL d from memory.
|
||||
func (d *DLL) Release() (err error) {
|
||||
return FreeLibrary(d.Handle)
|
||||
}
|
||||
|
||||
// A Proc implements access to a procedure inside a DLL.
|
||||
type Proc struct {
|
||||
Dll *DLL
|
||||
Name string
|
||||
addr uintptr
|
||||
}
|
||||
|
||||
// Addr returns the address of the procedure represented by p.
|
||||
// The return value can be passed to Syscall to run the procedure.
|
||||
func (p *Proc) Addr() uintptr {
|
||||
return p.addr
|
||||
}
|
||||
|
||||
//go:uintptrescapes
|
||||
|
||||
// Call executes procedure p with arguments a. It will panic, if more than 15 arguments
|
||||
// are supplied.
|
||||
//
|
||||
// The returned error is always non-nil, constructed from the result of GetLastError.
|
||||
// Callers must inspect the primary return value to decide whether an error occurred
|
||||
// (according to the semantics of the specific function being called) before consulting
|
||||
// the error. The error will be guaranteed to contain windows.Errno.
|
||||
func (p *Proc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
|
||||
switch len(a) {
|
||||
case 0:
|
||||
return syscall.Syscall(p.Addr(), uintptr(len(a)), 0, 0, 0)
|
||||
case 1:
|
||||
return syscall.Syscall(p.Addr(), uintptr(len(a)), a[0], 0, 0)
|
||||
case 2:
|
||||
return syscall.Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], 0)
|
||||
case 3:
|
||||
return syscall.Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], a[2])
|
||||
case 4:
|
||||
return syscall.Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], 0, 0)
|
||||
case 5:
|
||||
return syscall.Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], 0)
|
||||
case 6:
|
||||
return syscall.Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5])
|
||||
case 7:
|
||||
return syscall.Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], 0, 0)
|
||||
case 8:
|
||||
return syscall.Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], 0)
|
||||
case 9:
|
||||
return syscall.Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8])
|
||||
case 10:
|
||||
return syscall.Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], 0, 0)
|
||||
case 11:
|
||||
return syscall.Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], 0)
|
||||
case 12:
|
||||
return syscall.Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11])
|
||||
case 13:
|
||||
return syscall.Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], 0, 0)
|
||||
case 14:
|
||||
return syscall.Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], 0)
|
||||
case 15:
|
||||
return syscall.Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14])
|
||||
default:
|
||||
panic("Call " + p.Name + " with too many arguments " + itoa(len(a)) + ".")
|
||||
}
|
||||
}
|
||||
|
||||
// A LazyDLL implements access to a single DLL.
|
||||
// It will delay the load of the DLL until the first
|
||||
// call to its Handle method or to one of its
|
||||
// LazyProc's Addr method.
|
||||
type LazyDLL struct {
|
||||
Name string
|
||||
|
||||
// System determines whether the DLL must be loaded from the
|
||||
// Windows System directory, bypassing the normal DLL search
|
||||
// path.
|
||||
System bool
|
||||
|
||||
mu sync.Mutex
|
||||
dll *DLL // non nil once DLL is loaded
|
||||
}
|
||||
|
||||
// Load loads DLL file d.Name into memory. It returns an error if fails.
|
||||
// Load will not try to load DLL, if it is already loaded into memory.
|
||||
func (d *LazyDLL) Load() error {
|
||||
// Non-racy version of:
|
||||
// if d.dll != nil {
|
||||
if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll))) != nil {
|
||||
return nil
|
||||
}
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
if d.dll != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// kernel32.dll is special, since it's where LoadLibraryEx comes from.
|
||||
// The kernel already special-cases its name, so it's always
|
||||
// loaded from system32.
|
||||
var dll *DLL
|
||||
var err error
|
||||
if d.Name == "kernel32.dll" {
|
||||
dll, err = LoadDLL(d.Name)
|
||||
} else {
|
||||
dll, err = loadLibraryEx(d.Name, d.System)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Non-racy version of:
|
||||
// d.dll = dll
|
||||
atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll)), unsafe.Pointer(dll))
|
||||
return nil
|
||||
}
|
||||
|
||||
// mustLoad is like Load but panics if search fails.
|
||||
func (d *LazyDLL) mustLoad() {
|
||||
e := d.Load()
|
||||
if e != nil {
|
||||
panic(e)
|
||||
}
|
||||
}
|
||||
|
||||
// Handle returns d's module handle.
|
||||
func (d *LazyDLL) Handle() uintptr {
|
||||
d.mustLoad()
|
||||
return uintptr(d.dll.Handle)
|
||||
}
|
||||
|
||||
// NewProc returns a LazyProc for accessing the named procedure in the DLL d.
|
||||
func (d *LazyDLL) NewProc(name string) *LazyProc {
|
||||
return &LazyProc{l: d, Name: name}
|
||||
}
|
||||
|
||||
// NewLazyDLL creates new LazyDLL associated with DLL file.
|
||||
func NewLazyDLL(name string) *LazyDLL {
|
||||
return &LazyDLL{Name: name}
|
||||
}
|
||||
|
||||
// NewLazySystemDLL is like NewLazyDLL, but will only
|
||||
// search Windows System directory for the DLL if name is
|
||||
// a base name (like "advapi32.dll").
|
||||
func NewLazySystemDLL(name string) *LazyDLL {
|
||||
return &LazyDLL{Name: name, System: true}
|
||||
}
|
||||
|
||||
// A LazyProc implements access to a procedure inside a LazyDLL.
|
||||
// It delays the lookup until the Addr method is called.
|
||||
type LazyProc struct {
|
||||
Name string
|
||||
|
||||
mu sync.Mutex
|
||||
l *LazyDLL
|
||||
proc *Proc
|
||||
}
|
||||
|
||||
// Find searches DLL for procedure named p.Name. It returns
|
||||
// an error if search fails. Find will not search procedure,
|
||||
// if it is already found and loaded into memory.
|
||||
func (p *LazyProc) Find() error {
|
||||
// Non-racy version of:
|
||||
// if p.proc == nil {
|
||||
if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc))) == nil {
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
if p.proc == nil {
|
||||
e := p.l.Load()
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
proc, e := p.l.dll.FindProc(p.Name)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
// Non-racy version of:
|
||||
// p.proc = proc
|
||||
atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc)), unsafe.Pointer(proc))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// mustFind is like Find but panics if search fails.
|
||||
func (p *LazyProc) mustFind() {
|
||||
e := p.Find()
|
||||
if e != nil {
|
||||
panic(e)
|
||||
}
|
||||
}
|
||||
|
||||
// Addr returns the address of the procedure represented by p.
|
||||
// The return value can be passed to Syscall to run the procedure.
|
||||
// It will panic if the procedure cannot be found.
|
||||
func (p *LazyProc) Addr() uintptr {
|
||||
p.mustFind()
|
||||
return p.proc.Addr()
|
||||
}
|
||||
|
||||
//go:uintptrescapes
|
||||
|
||||
// Call executes procedure p with arguments a. It will panic, if more than 15 arguments
|
||||
// are supplied. It will also panic if the procedure cannot be found.
|
||||
//
|
||||
// The returned error is always non-nil, constructed from the result of GetLastError.
|
||||
// Callers must inspect the primary return value to decide whether an error occurred
|
||||
// (according to the semantics of the specific function being called) before consulting
|
||||
// the error. The error will be guaranteed to contain windows.Errno.
|
||||
func (p *LazyProc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
|
||||
p.mustFind()
|
||||
return p.proc.Call(a...)
|
||||
}
|
||||
|
||||
var canDoSearchSystem32Once struct {
|
||||
sync.Once
|
||||
v bool
|
||||
}
|
||||
|
||||
func initCanDoSearchSystem32() {
|
||||
// https://msdn.microsoft.com/en-us/library/ms684179(v=vs.85).aspx says:
|
||||
// "Windows 7, Windows Server 2008 R2, Windows Vista, and Windows
|
||||
// Server 2008: The LOAD_LIBRARY_SEARCH_* flags are available on
|
||||
// systems that have KB2533623 installed. To determine whether the
|
||||
// flags are available, use GetProcAddress to get the address of the
|
||||
// AddDllDirectory, RemoveDllDirectory, or SetDefaultDllDirectories
|
||||
// function. If GetProcAddress succeeds, the LOAD_LIBRARY_SEARCH_*
|
||||
// flags can be used with LoadLibraryEx."
|
||||
canDoSearchSystem32Once.v = (modkernel32.NewProc("AddDllDirectory").Find() == nil)
|
||||
}
|
||||
|
||||
func canDoSearchSystem32() bool {
|
||||
canDoSearchSystem32Once.Do(initCanDoSearchSystem32)
|
||||
return canDoSearchSystem32Once.v
|
||||
}
|
||||
|
||||
func isBaseName(name string) bool {
|
||||
for _, c := range name {
|
||||
if c == ':' || c == '/' || c == '\\' {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// loadLibraryEx wraps the Windows LoadLibraryEx function.
|
||||
//
|
||||
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms684179(v=vs.85).aspx
|
||||
//
|
||||
// If name is not an absolute path, LoadLibraryEx searches for the DLL
|
||||
// in a variety of automatic locations unless constrained by flags.
|
||||
// See: https://msdn.microsoft.com/en-us/library/ff919712%28VS.85%29.aspx
|
||||
func loadLibraryEx(name string, system bool) (*DLL, error) {
|
||||
loadDLL := name
|
||||
var flags uintptr
|
||||
if system {
|
||||
if canDoSearchSystem32() {
|
||||
const LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800
|
||||
flags = LOAD_LIBRARY_SEARCH_SYSTEM32
|
||||
} else if isBaseName(name) {
|
||||
// WindowsXP or unpatched Windows machine
|
||||
// trying to load "foo.dll" out of the system
|
||||
// folder, but LoadLibraryEx doesn't support
|
||||
// that yet on their system, so emulate it.
|
||||
systemdir, err := GetSystemDirectory()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
loadDLL = systemdir + "\\" + name
|
||||
}
|
||||
}
|
||||
h, err := LoadLibraryEx(loadDLL, 0, flags)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &DLL{Name: name, Handle: h}, nil
|
||||
}
|
||||
|
||||
type errString string
|
||||
|
||||
func (s errString) Error() string { return string(s) }
|
|
@ -0,0 +1,61 @@
|
|||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Windows environment variables.
|
||||
|
||||
package windows
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unicode/utf16"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func Getenv(key string) (value string, found bool) {
|
||||
return syscall.Getenv(key)
|
||||
}
|
||||
|
||||
func Setenv(key, value string) error {
|
||||
return syscall.Setenv(key, value)
|
||||
}
|
||||
|
||||
func Clearenv() {
|
||||
syscall.Clearenv()
|
||||
}
|
||||
|
||||
func Environ() []string {
|
||||
return syscall.Environ()
|
||||
}
|
||||
|
||||
// Returns a default environment associated with the token, rather than the current
|
||||
// process. If inheritExisting is true, then this environment also inherits the
|
||||
// environment of the current process.
|
||||
func (token Token) Environ(inheritExisting bool) (env []string, err error) {
|
||||
var block *uint16
|
||||
err = CreateEnvironmentBlock(&block, token, inheritExisting)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer DestroyEnvironmentBlock(block)
|
||||
blockp := uintptr(unsafe.Pointer(block))
|
||||
for {
|
||||
entry := (*[(1 << 30) - 1]uint16)(unsafe.Pointer(blockp))[:]
|
||||
for i, v := range entry {
|
||||
if v == 0 {
|
||||
entry = entry[:i]
|
||||
break
|
||||
}
|
||||
}
|
||||
if len(entry) == 0 {
|
||||
break
|
||||
}
|
||||
env = append(env, string(utf16.Decode(entry)))
|
||||
blockp += 2 * (uintptr(len(entry)) + 1)
|
||||
}
|
||||
return env, nil
|
||||
}
|
||||
|
||||
func Unsetenv(key string) error {
|
||||
return syscall.Unsetenv(key)
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build windows
|
||||
|
||||
package windows
|
||||
|
||||
const (
|
||||
EVENTLOG_SUCCESS = 0
|
||||
EVENTLOG_ERROR_TYPE = 1
|
||||
EVENTLOG_WARNING_TYPE = 2
|
||||
EVENTLOG_INFORMATION_TYPE = 4
|
||||
EVENTLOG_AUDIT_SUCCESS = 8
|
||||
EVENTLOG_AUDIT_FAILURE = 16
|
||||
)
|
||||
|
||||
//sys RegisterEventSource(uncServerName *uint16, sourceName *uint16) (handle Handle, err error) [failretval==0] = advapi32.RegisterEventSourceW
|
||||
//sys DeregisterEventSource(handle Handle) (err error) = advapi32.DeregisterEventSource
|
||||
//sys ReportEvent(log Handle, etype uint16, category uint16, eventId uint32, usrSId uintptr, numStrings uint16, dataSize uint32, strings **uint16, rawData *byte) (err error) = advapi32.ReportEventW
|
|
@ -0,0 +1,97 @@
|
|||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Fork, exec, wait, etc.
|
||||
|
||||
package windows
|
||||
|
||||
// EscapeArg rewrites command line argument s as prescribed
|
||||
// in http://msdn.microsoft.com/en-us/library/ms880421.
|
||||
// This function returns "" (2 double quotes) if s is empty.
|
||||
// Alternatively, these transformations are done:
|
||||
// - every back slash (\) is doubled, but only if immediately
|
||||
// followed by double quote (");
|
||||
// - every double quote (") is escaped by back slash (\);
|
||||
// - finally, s is wrapped with double quotes (arg -> "arg"),
|
||||
// but only if there is space or tab inside s.
|
||||
func EscapeArg(s string) string {
|
||||
if len(s) == 0 {
|
||||
return "\"\""
|
||||
}
|
||||
n := len(s)
|
||||
hasSpace := false
|
||||
for i := 0; i < len(s); i++ {
|
||||
switch s[i] {
|
||||
case '"', '\\':
|
||||
n++
|
||||
case ' ', '\t':
|
||||
hasSpace = true
|
||||
}
|
||||
}
|
||||
if hasSpace {
|
||||
n += 2
|
||||
}
|
||||
if n == len(s) {
|
||||
return s
|
||||
}
|
||||
|
||||
qs := make([]byte, n)
|
||||
j := 0
|
||||
if hasSpace {
|
||||
qs[j] = '"'
|
||||
j++
|
||||
}
|
||||
slashes := 0
|
||||
for i := 0; i < len(s); i++ {
|
||||
switch s[i] {
|
||||
default:
|
||||
slashes = 0
|
||||
qs[j] = s[i]
|
||||
case '\\':
|
||||
slashes++
|
||||
qs[j] = s[i]
|
||||
case '"':
|
||||
for ; slashes > 0; slashes-- {
|
||||
qs[j] = '\\'
|
||||
j++
|
||||
}
|
||||
qs[j] = '\\'
|
||||
j++
|
||||
qs[j] = s[i]
|
||||
}
|
||||
j++
|
||||
}
|
||||
if hasSpace {
|
||||
for ; slashes > 0; slashes-- {
|
||||
qs[j] = '\\'
|
||||
j++
|
||||
}
|
||||
qs[j] = '"'
|
||||
j++
|
||||
}
|
||||
return string(qs[:j])
|
||||
}
|
||||
|
||||
func CloseOnExec(fd Handle) {
|
||||
SetHandleInformation(Handle(fd), HANDLE_FLAG_INHERIT, 0)
|
||||
}
|
||||
|
||||
// FullPath retrieves the full path of the specified file.
|
||||
func FullPath(name string) (path string, err error) {
|
||||
p, err := UTF16PtrFromString(name)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
n := uint32(100)
|
||||
for {
|
||||
buf := make([]uint16, n)
|
||||
n, err = GetFullPathName(p, uint32(len(buf)), &buf[0], nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if n <= uint32(len(buf)) {
|
||||
return UTF16ToString(buf[:n]), nil
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package windows
|
||||
|
||||
const (
|
||||
MEM_COMMIT = 0x00001000
|
||||
MEM_RESERVE = 0x00002000
|
||||
MEM_DECOMMIT = 0x00004000
|
||||
MEM_RELEASE = 0x00008000
|
||||
MEM_RESET = 0x00080000
|
||||
MEM_TOP_DOWN = 0x00100000
|
||||
MEM_WRITE_WATCH = 0x00200000
|
||||
MEM_PHYSICAL = 0x00400000
|
||||
MEM_RESET_UNDO = 0x01000000
|
||||
MEM_LARGE_PAGES = 0x20000000
|
||||
|
||||
PAGE_NOACCESS = 0x01
|
||||
PAGE_READONLY = 0x02
|
||||
PAGE_READWRITE = 0x04
|
||||
PAGE_WRITECOPY = 0x08
|
||||
PAGE_EXECUTE_READ = 0x20
|
||||
PAGE_EXECUTE_READWRITE = 0x40
|
||||
PAGE_EXECUTE_WRITECOPY = 0x80
|
||||
)
|
|
@ -0,0 +1,63 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Copyright 2019 The Go Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style
|
||||
# license that can be found in the LICENSE file.
|
||||
|
||||
set -e
|
||||
shopt -s nullglob
|
||||
|
||||
winerror="$(printf '%s\n' "/mnt/c/Program Files (x86)/Windows Kits/"/*/Include/*/shared/winerror.h | sort -Vr | head -n 1)"
|
||||
[[ -n $winerror ]] || { echo "Unable to find winerror.h" >&2; exit 1; }
|
||||
|
||||
declare -A errors
|
||||
|
||||
{
|
||||
echo "// Code generated by 'mkerrors.bash'; DO NOT EDIT."
|
||||
echo
|
||||
echo "package windows"
|
||||
echo "import \"syscall\""
|
||||
echo "const ("
|
||||
|
||||
while read -r line; do
|
||||
unset vtype
|
||||
if [[ $line =~ ^#define\ +([A-Z0-9_]+k?)\ +([A-Z0-9_]+\()?([A-Z][A-Z0-9_]+k?)\)? ]]; then
|
||||
key="${BASH_REMATCH[1]}"
|
||||
value="${BASH_REMATCH[3]}"
|
||||
elif [[ $line =~ ^#define\ +([A-Z0-9_]+k?)\ +([A-Z0-9_]+\()?((0x)?[0-9A-Fa-f]+)L?\)? ]]; then
|
||||
key="${BASH_REMATCH[1]}"
|
||||
value="${BASH_REMATCH[3]}"
|
||||
vtype="${BASH_REMATCH[2]}"
|
||||
elif [[ $line =~ ^#define\ +([A-Z0-9_]+k?)\ +\(\(([A-Z]+)\)((0x)?[0-9A-Fa-f]+)L?\) ]]; then
|
||||
key="${BASH_REMATCH[1]}"
|
||||
value="${BASH_REMATCH[3]}"
|
||||
vtype="${BASH_REMATCH[2]}"
|
||||
else
|
||||
continue
|
||||
fi
|
||||
[[ -n $key && -n $value ]] || continue
|
||||
[[ -z ${errors["$key"]} ]] || continue
|
||||
errors["$key"]="$value"
|
||||
if [[ -v vtype ]]; then
|
||||
if [[ $key == FACILITY_* || $key == NO_ERROR ]]; then
|
||||
vtype=""
|
||||
elif [[ $vtype == *HANDLE* || $vtype == *HRESULT* ]]; then
|
||||
vtype="Handle"
|
||||
else
|
||||
vtype="syscall.Errno"
|
||||
fi
|
||||
last_vtype="$vtype"
|
||||
else
|
||||
vtype=""
|
||||
if [[ $last_vtype == Handle && $value == NO_ERROR ]]; then
|
||||
value="S_OK"
|
||||
elif [[ $last_vtype == syscall.Errno && $value == NO_ERROR ]]; then
|
||||
value="ERROR_SUCCESS"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "$key $vtype = $value"
|
||||
done < "$winerror"
|
||||
|
||||
echo ")"
|
||||
} | gofmt > "zerrors_windows.go"
|
|
@ -0,0 +1,27 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Copyright 2019 The Go Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style
|
||||
# license that can be found in the LICENSE file.
|
||||
|
||||
set -e
|
||||
shopt -s nullglob
|
||||
|
||||
knownfolders="$(printf '%s\n' "/mnt/c/Program Files (x86)/Windows Kits/"/*/Include/*/um/KnownFolders.h | sort -Vr | head -n 1)"
|
||||
[[ -n $knownfolders ]] || { echo "Unable to find KnownFolders.h" >&2; exit 1; }
|
||||
|
||||
{
|
||||
echo "// Code generated by 'mkknownfolderids.bash'; DO NOT EDIT."
|
||||
echo
|
||||
echo "package windows"
|
||||
echo "type KNOWNFOLDERID GUID"
|
||||
echo "var ("
|
||||
while read -r line; do
|
||||
[[ $line =~ DEFINE_KNOWN_FOLDER\((FOLDERID_[^,]+),[\t\ ]*(0x[^,]+),[\t\ ]*(0x[^,]+),[\t\ ]*(0x[^,]+),[\t\ ]*(0x[^,]+),[\t\ ]*(0x[^,]+),[\t\ ]*(0x[^,]+),[\t\ ]*(0x[^,]+),[\t\ ]*(0x[^,]+),[\t\ ]*(0x[^,]+),[\t\ ]*(0x[^,]+),[\t\ ]*(0x[^,]+)\) ]] || continue
|
||||
printf "%s = &KNOWNFOLDERID{0x%08x, 0x%04x, 0x%04x, [8]byte{0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x}}\n" \
|
||||
"${BASH_REMATCH[1]}" $(( "${BASH_REMATCH[2]}" )) $(( "${BASH_REMATCH[3]}" )) $(( "${BASH_REMATCH[4]}" )) \
|
||||
$(( "${BASH_REMATCH[5]}" )) $(( "${BASH_REMATCH[6]}" )) $(( "${BASH_REMATCH[7]}" )) $(( "${BASH_REMATCH[8]}" )) \
|
||||
$(( "${BASH_REMATCH[9]}" )) $(( "${BASH_REMATCH[10]}" )) $(( "${BASH_REMATCH[11]}" )) $(( "${BASH_REMATCH[12]}" ))
|
||||
done < "$knownfolders"
|
||||
echo ")"
|
||||
} | gofmt > "zknownfolderids_windows.go"
|
|
@ -0,0 +1,9 @@
|
|||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build generate
|
||||
|
||||
package windows
|
||||
|
||||
//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go eventlog.go service.go syscall_windows.go security_windows.go
|
|
@ -0,0 +1,30 @@
|
|||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build windows,race
|
||||
|
||||
package windows
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const raceenabled = true
|
||||
|
||||
func raceAcquire(addr unsafe.Pointer) {
|
||||
runtime.RaceAcquire(addr)
|
||||
}
|
||||
|
||||
func raceReleaseMerge(addr unsafe.Pointer) {
|
||||
runtime.RaceReleaseMerge(addr)
|
||||
}
|
||||
|
||||
func raceReadRange(addr unsafe.Pointer, len int) {
|
||||
runtime.RaceReadRange(addr, len)
|
||||
}
|
||||
|
||||
func raceWriteRange(addr unsafe.Pointer, len int) {
|
||||
runtime.RaceWriteRange(addr, len)
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build windows,!race
|
||||
|
||||
package windows
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const raceenabled = false
|
||||
|
||||
func raceAcquire(addr unsafe.Pointer) {
|
||||
}
|
||||
|
||||
func raceReleaseMerge(addr unsafe.Pointer) {
|
||||
}
|
||||
|
||||
func raceReadRange(addr unsafe.Pointer, len int) {
|
||||
}
|
||||
|
||||
func raceWriteRange(addr unsafe.Pointer, len int) {
|
||||
}
|
|
@ -0,0 +1,198 @@
|
|||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build windows
|
||||
|
||||
// Package registry provides access to the Windows registry.
|
||||
//
|
||||
// Here is a simple example, opening a registry key and reading a string value from it.
|
||||
//
|
||||
// k, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion`, registry.QUERY_VALUE)
|
||||
// if err != nil {
|
||||
// log.Fatal(err)
|
||||
// }
|
||||
// defer k.Close()
|
||||
//
|
||||
// s, _, err := k.GetStringValue("SystemRoot")
|
||||
// if err != nil {
|
||||
// log.Fatal(err)
|
||||
// }
|
||||
// fmt.Printf("Windows system root is %q\n", s)
|
||||
//
|
||||
package registry
|
||||
|
||||
import (
|
||||
"io"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
// Registry key security and access rights.
|
||||
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms724878.aspx
|
||||
// for details.
|
||||
ALL_ACCESS = 0xf003f
|
||||
CREATE_LINK = 0x00020
|
||||
CREATE_SUB_KEY = 0x00004
|
||||
ENUMERATE_SUB_KEYS = 0x00008
|
||||
EXECUTE = 0x20019
|
||||
NOTIFY = 0x00010
|
||||
QUERY_VALUE = 0x00001
|
||||
READ = 0x20019
|
||||
SET_VALUE = 0x00002
|
||||
WOW64_32KEY = 0x00200
|
||||
WOW64_64KEY = 0x00100
|
||||
WRITE = 0x20006
|
||||
)
|
||||
|
||||
// Key is a handle to an open Windows registry key.
|
||||
// Keys can be obtained by calling OpenKey; there are
|
||||
// also some predefined root keys such as CURRENT_USER.
|
||||
// Keys can be used directly in the Windows API.
|
||||
type Key syscall.Handle
|
||||
|
||||
const (
|
||||
// Windows defines some predefined root keys that are always open.
|
||||
// An application can use these keys as entry points to the registry.
|
||||
// Normally these keys are used in OpenKey to open new keys,
|
||||
// but they can also be used anywhere a Key is required.
|
||||
CLASSES_ROOT = Key(syscall.HKEY_CLASSES_ROOT)
|
||||
CURRENT_USER = Key(syscall.HKEY_CURRENT_USER)
|
||||
LOCAL_MACHINE = Key(syscall.HKEY_LOCAL_MACHINE)
|
||||
USERS = Key(syscall.HKEY_USERS)
|
||||
CURRENT_CONFIG = Key(syscall.HKEY_CURRENT_CONFIG)
|
||||
PERFORMANCE_DATA = Key(syscall.HKEY_PERFORMANCE_DATA)
|
||||
)
|
||||
|
||||
// Close closes open key k.
|
||||
func (k Key) Close() error {
|
||||
return syscall.RegCloseKey(syscall.Handle(k))
|
||||
}
|
||||
|
||||
// OpenKey opens a new key with path name relative to key k.
|
||||
// It accepts any open key, including CURRENT_USER and others,
|
||||
// and returns the new key and an error.
|
||||
// The access parameter specifies desired access rights to the
|
||||
// key to be opened.
|
||||
func OpenKey(k Key, path string, access uint32) (Key, error) {
|
||||
p, err := syscall.UTF16PtrFromString(path)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
var subkey syscall.Handle
|
||||
err = syscall.RegOpenKeyEx(syscall.Handle(k), p, 0, access, &subkey)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return Key(subkey), nil
|
||||
}
|
||||
|
||||
// OpenRemoteKey opens a predefined registry key on another
|
||||
// computer pcname. The key to be opened is specified by k, but
|
||||
// can only be one of LOCAL_MACHINE, PERFORMANCE_DATA or USERS.
|
||||
// If pcname is "", OpenRemoteKey returns local computer key.
|
||||
func OpenRemoteKey(pcname string, k Key) (Key, error) {
|
||||
var err error
|
||||
var p *uint16
|
||||
if pcname != "" {
|
||||
p, err = syscall.UTF16PtrFromString(`\\` + pcname)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
var remoteKey syscall.Handle
|
||||
err = regConnectRegistry(p, syscall.Handle(k), &remoteKey)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return Key(remoteKey), nil
|
||||
}
|
||||
|
||||
// ReadSubKeyNames returns the names of subkeys of key k.
|
||||
// The parameter n controls the number of returned names,
|
||||
// analogous to the way os.File.Readdirnames works.
|
||||
func (k Key) ReadSubKeyNames(n int) ([]string, error) {
|
||||
names := make([]string, 0)
|
||||
// Registry key size limit is 255 bytes and described there:
|
||||
// https://msdn.microsoft.com/library/windows/desktop/ms724872.aspx
|
||||
buf := make([]uint16, 256) //plus extra room for terminating zero byte
|
||||
loopItems:
|
||||
for i := uint32(0); ; i++ {
|
||||
if n > 0 {
|
||||
if len(names) == n {
|
||||
return names, nil
|
||||
}
|
||||
}
|
||||
l := uint32(len(buf))
|
||||
for {
|
||||
err := syscall.RegEnumKeyEx(syscall.Handle(k), i, &buf[0], &l, nil, nil, nil, nil)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
if err == syscall.ERROR_MORE_DATA {
|
||||
// Double buffer size and try again.
|
||||
l = uint32(2 * len(buf))
|
||||
buf = make([]uint16, l)
|
||||
continue
|
||||
}
|
||||
if err == _ERROR_NO_MORE_ITEMS {
|
||||
break loopItems
|
||||
}
|
||||
return names, err
|
||||
}
|
||||
names = append(names, syscall.UTF16ToString(buf[:l]))
|
||||
}
|
||||
if n > len(names) {
|
||||
return names, io.EOF
|
||||
}
|
||||
return names, nil
|
||||
}
|
||||
|
||||
// CreateKey creates a key named path under open key k.
|
||||
// CreateKey returns the new key and a boolean flag that reports
|
||||
// whether the key already existed.
|
||||
// The access parameter specifies the access rights for the key
|
||||
// to be created.
|
||||
func CreateKey(k Key, path string, access uint32) (newk Key, openedExisting bool, err error) {
|
||||
var h syscall.Handle
|
||||
var d uint32
|
||||
err = regCreateKeyEx(syscall.Handle(k), syscall.StringToUTF16Ptr(path),
|
||||
0, nil, _REG_OPTION_NON_VOLATILE, access, nil, &h, &d)
|
||||
if err != nil {
|
||||
return 0, false, err
|
||||
}
|
||||
return Key(h), d == _REG_OPENED_EXISTING_KEY, nil
|
||||
}
|
||||
|
||||
// DeleteKey deletes the subkey path of key k and its values.
|
||||
func DeleteKey(k Key, path string) error {
|
||||
return regDeleteKey(syscall.Handle(k), syscall.StringToUTF16Ptr(path))
|
||||
}
|
||||
|
||||
// A KeyInfo describes the statistics of a key. It is returned by Stat.
|
||||
type KeyInfo struct {
|
||||
SubKeyCount uint32
|
||||
MaxSubKeyLen uint32 // size of the key's subkey with the longest name, in Unicode characters, not including the terminating zero byte
|
||||
ValueCount uint32
|
||||
MaxValueNameLen uint32 // size of the key's longest value name, in Unicode characters, not including the terminating zero byte
|
||||
MaxValueLen uint32 // longest data component among the key's values, in bytes
|
||||
lastWriteTime syscall.Filetime
|
||||
}
|
||||
|
||||
// ModTime returns the key's last write time.
|
||||
func (ki *KeyInfo) ModTime() time.Time {
|
||||
return time.Unix(0, ki.lastWriteTime.Nanoseconds())
|
||||
}
|
||||
|
||||
// Stat retrieves information about the open key k.
|
||||
func (k Key) Stat() (*KeyInfo, error) {
|
||||
var ki KeyInfo
|
||||
err := syscall.RegQueryInfoKey(syscall.Handle(k), nil, nil, nil,
|
||||
&ki.SubKeyCount, &ki.MaxSubKeyLen, nil, &ki.ValueCount,
|
||||
&ki.MaxValueNameLen, &ki.MaxValueLen, nil, &ki.lastWriteTime)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &ki, nil
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build generate
|
||||
|
||||
package registry
|
||||
|
||||
//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go syscall.go
|
|
@ -0,0 +1,32 @@
|
|||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build windows
|
||||
|
||||
package registry
|
||||
|
||||
import "syscall"
|
||||
|
||||
const (
|
||||
_REG_OPTION_NON_VOLATILE = 0
|
||||
|
||||
_REG_CREATED_NEW_KEY = 1
|
||||
_REG_OPENED_EXISTING_KEY = 2
|
||||
|
||||
_ERROR_NO_MORE_ITEMS syscall.Errno = 259
|
||||
)
|
||||
|
||||
func LoadRegLoadMUIString() error {
|
||||
return procRegLoadMUIStringW.Find()
|
||||
}
|
||||
|
||||
//sys regCreateKeyEx(key syscall.Handle, subkey *uint16, reserved uint32, class *uint16, options uint32, desired uint32, sa *syscall.SecurityAttributes, result *syscall.Handle, disposition *uint32) (regerrno error) = advapi32.RegCreateKeyExW
|
||||
//sys regDeleteKey(key syscall.Handle, subkey *uint16) (regerrno error) = advapi32.RegDeleteKeyW
|
||||
//sys regSetValueEx(key syscall.Handle, valueName *uint16, reserved uint32, vtype uint32, buf *byte, bufsize uint32) (regerrno error) = advapi32.RegSetValueExW
|
||||
//sys regEnumValue(key syscall.Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, valtype *uint32, buf *byte, buflen *uint32) (regerrno error) = advapi32.RegEnumValueW
|
||||
//sys regDeleteValue(key syscall.Handle, name *uint16) (regerrno error) = advapi32.RegDeleteValueW
|
||||
//sys regLoadMUIString(key syscall.Handle, name *uint16, buf *uint16, buflen uint32, buflenCopied *uint32, flags uint32, dir *uint16) (regerrno error) = advapi32.RegLoadMUIStringW
|
||||
//sys regConnectRegistry(machinename *uint16, key syscall.Handle, result *syscall.Handle) (regerrno error) = advapi32.RegConnectRegistryW
|
||||
|
||||
//sys expandEnvironmentStrings(src *uint16, dst *uint16, size uint32) (n uint32, err error) = kernel32.ExpandEnvironmentStringsW
|
|
@ -0,0 +1,387 @@
|
|||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build windows
|
||||
|
||||
package registry
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"syscall"
|
||||
"unicode/utf16"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
// Registry value types.
|
||||
NONE = 0
|
||||
SZ = 1
|
||||
EXPAND_SZ = 2
|
||||
BINARY = 3
|
||||
DWORD = 4
|
||||
DWORD_BIG_ENDIAN = 5
|
||||
LINK = 6
|
||||
MULTI_SZ = 7
|
||||
RESOURCE_LIST = 8
|
||||
FULL_RESOURCE_DESCRIPTOR = 9
|
||||
RESOURCE_REQUIREMENTS_LIST = 10
|
||||
QWORD = 11
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrShortBuffer is returned when the buffer was too short for the operation.
|
||||
ErrShortBuffer = syscall.ERROR_MORE_DATA
|
||||
|
||||
// ErrNotExist is returned when a registry key or value does not exist.
|
||||
ErrNotExist = syscall.ERROR_FILE_NOT_FOUND
|
||||
|
||||
// ErrUnexpectedType is returned by Get*Value when the value's type was unexpected.
|
||||
ErrUnexpectedType = errors.New("unexpected key value type")
|
||||
)
|
||||
|
||||
// GetValue retrieves the type and data for the specified value associated
|
||||
// with an open key k. It fills up buffer buf and returns the retrieved
|
||||
// byte count n. If buf is too small to fit the stored value it returns
|
||||
// ErrShortBuffer error along with the required buffer size n.
|
||||
// If no buffer is provided, it returns true and actual buffer size n.
|
||||
// If no buffer is provided, GetValue returns the value's type only.
|
||||
// If the value does not exist, the error returned is ErrNotExist.
|
||||
//
|
||||
// GetValue is a low level function. If value's type is known, use the appropriate
|
||||
// Get*Value function instead.
|
||||
func (k Key) GetValue(name string, buf []byte) (n int, valtype uint32, err error) {
|
||||
pname, err := syscall.UTF16PtrFromString(name)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
var pbuf *byte
|
||||
if len(buf) > 0 {
|
||||
pbuf = (*byte)(unsafe.Pointer(&buf[0]))
|
||||
}
|
||||
l := uint32(len(buf))
|
||||
err = syscall.RegQueryValueEx(syscall.Handle(k), pname, nil, &valtype, pbuf, &l)
|
||||
if err != nil {
|
||||
return int(l), valtype, err
|
||||
}
|
||||
return int(l), valtype, nil
|
||||
}
|
||||
|
||||
func (k Key) getValue(name string, buf []byte) (data []byte, valtype uint32, err error) {
|
||||
p, err := syscall.UTF16PtrFromString(name)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
var t uint32
|
||||
n := uint32(len(buf))
|
||||
for {
|
||||
err = syscall.RegQueryValueEx(syscall.Handle(k), p, nil, &t, (*byte)(unsafe.Pointer(&buf[0])), &n)
|
||||
if err == nil {
|
||||
return buf[:n], t, nil
|
||||
}
|
||||
if err != syscall.ERROR_MORE_DATA {
|
||||
return nil, 0, err
|
||||
}
|
||||
if n <= uint32(len(buf)) {
|
||||
return nil, 0, err
|
||||
}
|
||||
buf = make([]byte, n)
|
||||
}
|
||||
}
|
||||
|
||||
// GetStringValue retrieves the string value for the specified
|
||||
// value name associated with an open key k. It also returns the value's type.
|
||||
// If value does not exist, GetStringValue returns ErrNotExist.
|
||||
// If value is not SZ or EXPAND_SZ, it will return the correct value
|
||||
// type and ErrUnexpectedType.
|
||||
func (k Key) GetStringValue(name string) (val string, valtype uint32, err error) {
|
||||
data, typ, err2 := k.getValue(name, make([]byte, 64))
|
||||
if err2 != nil {
|
||||
return "", typ, err2
|
||||
}
|
||||
switch typ {
|
||||
case SZ, EXPAND_SZ:
|
||||
default:
|
||||
return "", typ, ErrUnexpectedType
|
||||
}
|
||||
if len(data) == 0 {
|
||||
return "", typ, nil
|
||||
}
|
||||
u := (*[1 << 29]uint16)(unsafe.Pointer(&data[0]))[:]
|
||||
return syscall.UTF16ToString(u), typ, nil
|
||||
}
|
||||
|
||||
// GetMUIStringValue retrieves the localized string value for
|
||||
// the specified value name associated with an open key k.
|
||||
// If the value name doesn't exist or the localized string value
|
||||
// can't be resolved, GetMUIStringValue returns ErrNotExist.
|
||||
// GetMUIStringValue panics if the system doesn't support
|
||||
// regLoadMUIString; use LoadRegLoadMUIString to check if
|
||||
// regLoadMUIString is supported before calling this function.
|
||||
func (k Key) GetMUIStringValue(name string) (string, error) {
|
||||
pname, err := syscall.UTF16PtrFromString(name)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
buf := make([]uint16, 1024)
|
||||
var buflen uint32
|
||||
var pdir *uint16
|
||||
|
||||
err = regLoadMUIString(syscall.Handle(k), pname, &buf[0], uint32(len(buf)), &buflen, 0, pdir)
|
||||
if err == syscall.ERROR_FILE_NOT_FOUND { // Try fallback path
|
||||
|
||||
// Try to resolve the string value using the system directory as
|
||||
// a DLL search path; this assumes the string value is of the form
|
||||
// @[path]\dllname,-strID but with no path given, e.g. @tzres.dll,-320.
|
||||
|
||||
// This approach works with tzres.dll but may have to be revised
|
||||
// in the future to allow callers to provide custom search paths.
|
||||
|
||||
var s string
|
||||
s, err = ExpandString("%SystemRoot%\\system32\\")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
pdir, err = syscall.UTF16PtrFromString(s)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
err = regLoadMUIString(syscall.Handle(k), pname, &buf[0], uint32(len(buf)), &buflen, 0, pdir)
|
||||
}
|
||||
|
||||
for err == syscall.ERROR_MORE_DATA { // Grow buffer if needed
|
||||
if buflen <= uint32(len(buf)) {
|
||||
break // Buffer not growing, assume race; break
|
||||
}
|
||||
buf = make([]uint16, buflen)
|
||||
err = regLoadMUIString(syscall.Handle(k), pname, &buf[0], uint32(len(buf)), &buflen, 0, pdir)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return syscall.UTF16ToString(buf), nil
|
||||
}
|
||||
|
||||
// ExpandString expands environment-variable strings and replaces
|
||||
// them with the values defined for the current user.
|
||||
// Use ExpandString to expand EXPAND_SZ strings.
|
||||
func ExpandString(value string) (string, error) {
|
||||
if value == "" {
|
||||
return "", nil
|
||||
}
|
||||
p, err := syscall.UTF16PtrFromString(value)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
r := make([]uint16, 100)
|
||||
for {
|
||||
n, err := expandEnvironmentStrings(p, &r[0], uint32(len(r)))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if n <= uint32(len(r)) {
|
||||
u := (*[1 << 29]uint16)(unsafe.Pointer(&r[0]))[:]
|
||||
return syscall.UTF16ToString(u), nil
|
||||
}
|
||||
r = make([]uint16, n)
|
||||
}
|
||||
}
|
||||
|
||||
// GetStringsValue retrieves the []string value for the specified
|
||||
// value name associated with an open key k. It also returns the value's type.
|
||||
// If value does not exist, GetStringsValue returns ErrNotExist.
|
||||
// If value is not MULTI_SZ, it will return the correct value
|
||||
// type and ErrUnexpectedType.
|
||||
func (k Key) GetStringsValue(name string) (val []string, valtype uint32, err error) {
|
||||
data, typ, err2 := k.getValue(name, make([]byte, 64))
|
||||
if err2 != nil {
|
||||
return nil, typ, err2
|
||||
}
|
||||
if typ != MULTI_SZ {
|
||||
return nil, typ, ErrUnexpectedType
|
||||
}
|
||||
if len(data) == 0 {
|
||||
return nil, typ, nil
|
||||
}
|
||||
p := (*[1 << 29]uint16)(unsafe.Pointer(&data[0]))[:len(data)/2]
|
||||
if len(p) == 0 {
|
||||
return nil, typ, nil
|
||||
}
|
||||
if p[len(p)-1] == 0 {
|
||||
p = p[:len(p)-1] // remove terminating null
|
||||
}
|
||||
val = make([]string, 0, 5)
|
||||
from := 0
|
||||
for i, c := range p {
|
||||
if c == 0 {
|
||||
val = append(val, string(utf16.Decode(p[from:i])))
|
||||
from = i + 1
|
||||
}
|
||||
}
|
||||
return val, typ, nil
|
||||
}
|
||||
|
||||
// GetIntegerValue retrieves the integer value for the specified
|
||||
// value name associated with an open key k. It also returns the value's type.
|
||||
// If value does not exist, GetIntegerValue returns ErrNotExist.
|
||||
// If value is not DWORD or QWORD, it will return the correct value
|
||||
// type and ErrUnexpectedType.
|
||||
func (k Key) GetIntegerValue(name string) (val uint64, valtype uint32, err error) {
|
||||
data, typ, err2 := k.getValue(name, make([]byte, 8))
|
||||
if err2 != nil {
|
||||
return 0, typ, err2
|
||||
}
|
||||
switch typ {
|
||||
case DWORD:
|
||||
if len(data) != 4 {
|
||||
return 0, typ, errors.New("DWORD value is not 4 bytes long")
|
||||
}
|
||||
var val32 uint32
|
||||
copy((*[4]byte)(unsafe.Pointer(&val32))[:], data)
|
||||
return uint64(val32), DWORD, nil
|
||||
case QWORD:
|
||||
if len(data) != 8 {
|
||||
return 0, typ, errors.New("QWORD value is not 8 bytes long")
|
||||
}
|
||||
copy((*[8]byte)(unsafe.Pointer(&val))[:], data)
|
||||
return val, QWORD, nil
|
||||
default:
|
||||
return 0, typ, ErrUnexpectedType
|
||||
}
|
||||
}
|
||||
|
||||
// GetBinaryValue retrieves the binary value for the specified
|
||||
// value name associated with an open key k. It also returns the value's type.
|
||||
// If value does not exist, GetBinaryValue returns ErrNotExist.
|
||||
// If value is not BINARY, it will return the correct value
|
||||
// type and ErrUnexpectedType.
|
||||
func (k Key) GetBinaryValue(name string) (val []byte, valtype uint32, err error) {
|
||||
data, typ, err2 := k.getValue(name, make([]byte, 64))
|
||||
if err2 != nil {
|
||||
return nil, typ, err2
|
||||
}
|
||||
if typ != BINARY {
|
||||
return nil, typ, ErrUnexpectedType
|
||||
}
|
||||
return data, typ, nil
|
||||
}
|
||||
|
||||
func (k Key) setValue(name string, valtype uint32, data []byte) error {
|
||||
p, err := syscall.UTF16PtrFromString(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(data) == 0 {
|
||||
return regSetValueEx(syscall.Handle(k), p, 0, valtype, nil, 0)
|
||||
}
|
||||
return regSetValueEx(syscall.Handle(k), p, 0, valtype, &data[0], uint32(len(data)))
|
||||
}
|
||||
|
||||
// SetDWordValue sets the data and type of a name value
|
||||
// under key k to value and DWORD.
|
||||
func (k Key) SetDWordValue(name string, value uint32) error {
|
||||
return k.setValue(name, DWORD, (*[4]byte)(unsafe.Pointer(&value))[:])
|
||||
}
|
||||
|
||||
// SetQWordValue sets the data and type of a name value
|
||||
// under key k to value and QWORD.
|
||||
func (k Key) SetQWordValue(name string, value uint64) error {
|
||||
return k.setValue(name, QWORD, (*[8]byte)(unsafe.Pointer(&value))[:])
|
||||
}
|
||||
|
||||
func (k Key) setStringValue(name string, valtype uint32, value string) error {
|
||||
v, err := syscall.UTF16FromString(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
buf := (*[1 << 29]byte)(unsafe.Pointer(&v[0]))[:len(v)*2]
|
||||
return k.setValue(name, valtype, buf)
|
||||
}
|
||||
|
||||
// SetStringValue sets the data and type of a name value
|
||||
// under key k to value and SZ. The value must not contain a zero byte.
|
||||
func (k Key) SetStringValue(name, value string) error {
|
||||
return k.setStringValue(name, SZ, value)
|
||||
}
|
||||
|
||||
// SetExpandStringValue sets the data and type of a name value
|
||||
// under key k to value and EXPAND_SZ. The value must not contain a zero byte.
|
||||
func (k Key) SetExpandStringValue(name, value string) error {
|
||||
return k.setStringValue(name, EXPAND_SZ, value)
|
||||
}
|
||||
|
||||
// SetStringsValue sets the data and type of a name value
|
||||
// under key k to value and MULTI_SZ. The value strings
|
||||
// must not contain a zero byte.
|
||||
func (k Key) SetStringsValue(name string, value []string) error {
|
||||
ss := ""
|
||||
for _, s := range value {
|
||||
for i := 0; i < len(s); i++ {
|
||||
if s[i] == 0 {
|
||||
return errors.New("string cannot have 0 inside")
|
||||
}
|
||||
}
|
||||
ss += s + "\x00"
|
||||
}
|
||||
v := utf16.Encode([]rune(ss + "\x00"))
|
||||
buf := (*[1 << 29]byte)(unsafe.Pointer(&v[0]))[:len(v)*2]
|
||||
return k.setValue(name, MULTI_SZ, buf)
|
||||
}
|
||||
|
||||
// SetBinaryValue sets the data and type of a name value
|
||||
// under key k to value and BINARY.
|
||||
func (k Key) SetBinaryValue(name string, value []byte) error {
|
||||
return k.setValue(name, BINARY, value)
|
||||
}
|
||||
|
||||
// DeleteValue removes a named value from the key k.
|
||||
func (k Key) DeleteValue(name string) error {
|
||||
return regDeleteValue(syscall.Handle(k), syscall.StringToUTF16Ptr(name))
|
||||
}
|
||||
|
||||
// ReadValueNames returns the value names of key k.
|
||||
// The parameter n controls the number of returned names,
|
||||
// analogous to the way os.File.Readdirnames works.
|
||||
func (k Key) ReadValueNames(n int) ([]string, error) {
|
||||
ki, err := k.Stat()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
names := make([]string, 0, ki.ValueCount)
|
||||
buf := make([]uint16, ki.MaxValueNameLen+1) // extra room for terminating null character
|
||||
loopItems:
|
||||
for i := uint32(0); ; i++ {
|
||||
if n > 0 {
|
||||
if len(names) == n {
|
||||
return names, nil
|
||||
}
|
||||
}
|
||||
l := uint32(len(buf))
|
||||
for {
|
||||
err := regEnumValue(syscall.Handle(k), i, &buf[0], &l, nil, nil, nil, nil)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
if err == syscall.ERROR_MORE_DATA {
|
||||
// Double buffer size and try again.
|
||||
l = uint32(2 * len(buf))
|
||||
buf = make([]uint16, l)
|
||||
continue
|
||||
}
|
||||
if err == _ERROR_NO_MORE_ITEMS {
|
||||
break loopItems
|
||||
}
|
||||
return names, err
|
||||
}
|
||||
names = append(names, syscall.UTF16ToString(buf[:l]))
|
||||
}
|
||||
if n > len(names) {
|
||||
return names, io.EOF
|
||||
}
|
||||
return names, nil
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
// Code generated by 'go generate'; DO NOT EDIT.
|
||||
|
||||
package registry
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
var _ unsafe.Pointer
|
||||
|
||||
// Do the interface allocations only once for common
|
||||
// Errno values.
|
||||
const (
|
||||
errnoERROR_IO_PENDING = 997
|
||||
)
|
||||
|
||||
var (
|
||||
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
|
||||
)
|
||||
|
||||
// errnoErr returns common boxed Errno values, to prevent
|
||||
// allocations at runtime.
|
||||
func errnoErr(e syscall.Errno) error {
|
||||
switch e {
|
||||
case 0:
|
||||
return nil
|
||||
case errnoERROR_IO_PENDING:
|
||||
return errERROR_IO_PENDING
|
||||
}
|
||||
// TODO: add more here, after collecting data on the common
|
||||
// error values see on Windows. (perhaps when running
|
||||
// all.bat?)
|
||||
return e
|
||||
}
|
||||
|
||||
var (
|
||||
modadvapi32 = windows.NewLazySystemDLL("advapi32.dll")
|
||||
modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
|
||||
|
||||
procRegCreateKeyExW = modadvapi32.NewProc("RegCreateKeyExW")
|
||||
procRegDeleteKeyW = modadvapi32.NewProc("RegDeleteKeyW")
|
||||
procRegSetValueExW = modadvapi32.NewProc("RegSetValueExW")
|
||||
procRegEnumValueW = modadvapi32.NewProc("RegEnumValueW")
|
||||
procRegDeleteValueW = modadvapi32.NewProc("RegDeleteValueW")
|
||||
procRegLoadMUIStringW = modadvapi32.NewProc("RegLoadMUIStringW")
|
||||
procRegConnectRegistryW = modadvapi32.NewProc("RegConnectRegistryW")
|
||||
procExpandEnvironmentStringsW = modkernel32.NewProc("ExpandEnvironmentStringsW")
|
||||
)
|
||||
|
||||
func regCreateKeyEx(key syscall.Handle, subkey *uint16, reserved uint32, class *uint16, options uint32, desired uint32, sa *syscall.SecurityAttributes, result *syscall.Handle, disposition *uint32) (regerrno error) {
|
||||
r0, _, _ := syscall.Syscall9(procRegCreateKeyExW.Addr(), 9, uintptr(key), uintptr(unsafe.Pointer(subkey)), uintptr(reserved), uintptr(unsafe.Pointer(class)), uintptr(options), uintptr(desired), uintptr(unsafe.Pointer(sa)), uintptr(unsafe.Pointer(result)), uintptr(unsafe.Pointer(disposition)))
|
||||
if r0 != 0 {
|
||||
regerrno = syscall.Errno(r0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func regDeleteKey(key syscall.Handle, subkey *uint16) (regerrno error) {
|
||||
r0, _, _ := syscall.Syscall(procRegDeleteKeyW.Addr(), 2, uintptr(key), uintptr(unsafe.Pointer(subkey)), 0)
|
||||
if r0 != 0 {
|
||||
regerrno = syscall.Errno(r0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func regSetValueEx(key syscall.Handle, valueName *uint16, reserved uint32, vtype uint32, buf *byte, bufsize uint32) (regerrno error) {
|
||||
r0, _, _ := syscall.Syscall6(procRegSetValueExW.Addr(), 6, uintptr(key), uintptr(unsafe.Pointer(valueName)), uintptr(reserved), uintptr(vtype), uintptr(unsafe.Pointer(buf)), uintptr(bufsize))
|
||||
if r0 != 0 {
|
||||
regerrno = syscall.Errno(r0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func regEnumValue(key syscall.Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, valtype *uint32, buf *byte, buflen *uint32) (regerrno error) {
|
||||
r0, _, _ := syscall.Syscall9(procRegEnumValueW.Addr(), 8, uintptr(key), uintptr(index), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameLen)), uintptr(unsafe.Pointer(reserved)), uintptr(unsafe.Pointer(valtype)), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(buflen)), 0)
|
||||
if r0 != 0 {
|
||||
regerrno = syscall.Errno(r0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func regDeleteValue(key syscall.Handle, name *uint16) (regerrno error) {
|
||||
r0, _, _ := syscall.Syscall(procRegDeleteValueW.Addr(), 2, uintptr(key), uintptr(unsafe.Pointer(name)), 0)
|
||||
if r0 != 0 {
|
||||
regerrno = syscall.Errno(r0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func regLoadMUIString(key syscall.Handle, name *uint16, buf *uint16, buflen uint32, buflenCopied *uint32, flags uint32, dir *uint16) (regerrno error) {
|
||||
r0, _, _ := syscall.Syscall9(procRegLoadMUIStringW.Addr(), 7, uintptr(key), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(buf)), uintptr(buflen), uintptr(unsafe.Pointer(buflenCopied)), uintptr(flags), uintptr(unsafe.Pointer(dir)), 0, 0)
|
||||
if r0 != 0 {
|
||||
regerrno = syscall.Errno(r0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func regConnectRegistry(machinename *uint16, key syscall.Handle, result *syscall.Handle) (regerrno error) {
|
||||
r0, _, _ := syscall.Syscall(procRegConnectRegistryW.Addr(), 3, uintptr(unsafe.Pointer(machinename)), uintptr(key), uintptr(unsafe.Pointer(result)))
|
||||
if r0 != 0 {
|
||||
regerrno = syscall.Errno(r0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func expandEnvironmentStrings(src *uint16, dst *uint16, size uint32) (n uint32, err error) {
|
||||
r0, _, e1 := syscall.Syscall(procExpandEnvironmentStringsW.Addr(), 3, uintptr(unsafe.Pointer(src)), uintptr(unsafe.Pointer(dst)), uintptr(size))
|
||||
n = uint32(r0)
|
||||
if n == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
|
@ -0,0 +1,854 @@
|
|||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package windows
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
STANDARD_RIGHTS_REQUIRED = 0xf0000
|
||||
STANDARD_RIGHTS_READ = 0x20000
|
||||
STANDARD_RIGHTS_WRITE = 0x20000
|
||||
STANDARD_RIGHTS_EXECUTE = 0x20000
|
||||
STANDARD_RIGHTS_ALL = 0x1F0000
|
||||
)
|
||||
|
||||
const (
|
||||
NameUnknown = 0
|
||||
NameFullyQualifiedDN = 1
|
||||
NameSamCompatible = 2
|
||||
NameDisplay = 3
|
||||
NameUniqueId = 6
|
||||
NameCanonical = 7
|
||||
NameUserPrincipal = 8
|
||||
NameCanonicalEx = 9
|
||||
NameServicePrincipal = 10
|
||||
NameDnsDomain = 12
|
||||
)
|
||||
|
||||
// This function returns 1 byte BOOLEAN rather than the 4 byte BOOL.
|
||||
// http://blogs.msdn.com/b/drnick/archive/2007/12/19/windows-and-upn-format-credentials.aspx
|
||||
//sys TranslateName(accName *uint16, accNameFormat uint32, desiredNameFormat uint32, translatedName *uint16, nSize *uint32) (err error) [failretval&0xff==0] = secur32.TranslateNameW
|
||||
//sys GetUserNameEx(nameFormat uint32, nameBuffre *uint16, nSize *uint32) (err error) [failretval&0xff==0] = secur32.GetUserNameExW
|
||||
|
||||
// TranslateAccountName converts a directory service
|
||||
// object name from one format to another.
|
||||
func TranslateAccountName(username string, from, to uint32, initSize int) (string, error) {
|
||||
u, e := UTF16PtrFromString(username)
|
||||
if e != nil {
|
||||
return "", e
|
||||
}
|
||||
n := uint32(50)
|
||||
for {
|
||||
b := make([]uint16, n)
|
||||
e = TranslateName(u, from, to, &b[0], &n)
|
||||
if e == nil {
|
||||
return UTF16ToString(b[:n]), nil
|
||||
}
|
||||
if e != ERROR_INSUFFICIENT_BUFFER {
|
||||
return "", e
|
||||
}
|
||||
if n <= uint32(len(b)) {
|
||||
return "", e
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
// do not reorder
|
||||
NetSetupUnknownStatus = iota
|
||||
NetSetupUnjoined
|
||||
NetSetupWorkgroupName
|
||||
NetSetupDomainName
|
||||
)
|
||||
|
||||
type UserInfo10 struct {
|
||||
Name *uint16
|
||||
Comment *uint16
|
||||
UsrComment *uint16
|
||||
FullName *uint16
|
||||
}
|
||||
|
||||
//sys NetUserGetInfo(serverName *uint16, userName *uint16, level uint32, buf **byte) (neterr error) = netapi32.NetUserGetInfo
|
||||
//sys NetGetJoinInformation(server *uint16, name **uint16, bufType *uint32) (neterr error) = netapi32.NetGetJoinInformation
|
||||
//sys NetApiBufferFree(buf *byte) (neterr error) = netapi32.NetApiBufferFree
|
||||
|
||||
const (
|
||||
// do not reorder
|
||||
SidTypeUser = 1 + iota
|
||||
SidTypeGroup
|
||||
SidTypeDomain
|
||||
SidTypeAlias
|
||||
SidTypeWellKnownGroup
|
||||
SidTypeDeletedAccount
|
||||
SidTypeInvalid
|
||||
SidTypeUnknown
|
||||
SidTypeComputer
|
||||
SidTypeLabel
|
||||
)
|
||||
|
||||
type SidIdentifierAuthority struct {
|
||||
Value [6]byte
|
||||
}
|
||||
|
||||
var (
|
||||
SECURITY_NULL_SID_AUTHORITY = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 0}}
|
||||
SECURITY_WORLD_SID_AUTHORITY = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 1}}
|
||||
SECURITY_LOCAL_SID_AUTHORITY = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 2}}
|
||||
SECURITY_CREATOR_SID_AUTHORITY = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 3}}
|
||||
SECURITY_NON_UNIQUE_AUTHORITY = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 4}}
|
||||
SECURITY_NT_AUTHORITY = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 5}}
|
||||
SECURITY_MANDATORY_LABEL_AUTHORITY = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 16}}
|
||||
)
|
||||
|
||||
const (
|
||||
SECURITY_NULL_RID = 0
|
||||
SECURITY_WORLD_RID = 0
|
||||
SECURITY_LOCAL_RID = 0
|
||||
SECURITY_CREATOR_OWNER_RID = 0
|
||||
SECURITY_CREATOR_GROUP_RID = 1
|
||||
SECURITY_DIALUP_RID = 1
|
||||
SECURITY_NETWORK_RID = 2
|
||||
SECURITY_BATCH_RID = 3
|
||||
SECURITY_INTERACTIVE_RID = 4
|
||||
SECURITY_LOGON_IDS_RID = 5
|
||||
SECURITY_SERVICE_RID = 6
|
||||
SECURITY_LOCAL_SYSTEM_RID = 18
|
||||
SECURITY_BUILTIN_DOMAIN_RID = 32
|
||||
SECURITY_PRINCIPAL_SELF_RID = 10
|
||||
SECURITY_CREATOR_OWNER_SERVER_RID = 0x2
|
||||
SECURITY_CREATOR_GROUP_SERVER_RID = 0x3
|
||||
SECURITY_LOGON_IDS_RID_COUNT = 0x3
|
||||
SECURITY_ANONYMOUS_LOGON_RID = 0x7
|
||||
SECURITY_PROXY_RID = 0x8
|
||||
SECURITY_ENTERPRISE_CONTROLLERS_RID = 0x9
|
||||
SECURITY_SERVER_LOGON_RID = SECURITY_ENTERPRISE_CONTROLLERS_RID
|
||||
SECURITY_AUTHENTICATED_USER_RID = 0xb
|
||||
SECURITY_RESTRICTED_CODE_RID = 0xc
|
||||
SECURITY_NT_NON_UNIQUE_RID = 0x15
|
||||
)
|
||||
|
||||
// Predefined domain-relative RIDs for local groups.
|
||||
// See https://msdn.microsoft.com/en-us/library/windows/desktop/aa379649(v=vs.85).aspx
|
||||
const (
|
||||
DOMAIN_ALIAS_RID_ADMINS = 0x220
|
||||
DOMAIN_ALIAS_RID_USERS = 0x221
|
||||
DOMAIN_ALIAS_RID_GUESTS = 0x222
|
||||
DOMAIN_ALIAS_RID_POWER_USERS = 0x223
|
||||
DOMAIN_ALIAS_RID_ACCOUNT_OPS = 0x224
|
||||
DOMAIN_ALIAS_RID_SYSTEM_OPS = 0x225
|
||||
DOMAIN_ALIAS_RID_PRINT_OPS = 0x226
|
||||
DOMAIN_ALIAS_RID_BACKUP_OPS = 0x227
|
||||
DOMAIN_ALIAS_RID_REPLICATOR = 0x228
|
||||
DOMAIN_ALIAS_RID_RAS_SERVERS = 0x229
|
||||
DOMAIN_ALIAS_RID_PREW2KCOMPACCESS = 0x22a
|
||||
DOMAIN_ALIAS_RID_REMOTE_DESKTOP_USERS = 0x22b
|
||||
DOMAIN_ALIAS_RID_NETWORK_CONFIGURATION_OPS = 0x22c
|
||||
DOMAIN_ALIAS_RID_INCOMING_FOREST_TRUST_BUILDERS = 0x22d
|
||||
DOMAIN_ALIAS_RID_MONITORING_USERS = 0x22e
|
||||
DOMAIN_ALIAS_RID_LOGGING_USERS = 0x22f
|
||||
DOMAIN_ALIAS_RID_AUTHORIZATIONACCESS = 0x230
|
||||
DOMAIN_ALIAS_RID_TS_LICENSE_SERVERS = 0x231
|
||||
DOMAIN_ALIAS_RID_DCOM_USERS = 0x232
|
||||
DOMAIN_ALIAS_RID_IUSERS = 0x238
|
||||
DOMAIN_ALIAS_RID_CRYPTO_OPERATORS = 0x239
|
||||
DOMAIN_ALIAS_RID_CACHEABLE_PRINCIPALS_GROUP = 0x23b
|
||||
DOMAIN_ALIAS_RID_NON_CACHEABLE_PRINCIPALS_GROUP = 0x23c
|
||||
DOMAIN_ALIAS_RID_EVENT_LOG_READERS_GROUP = 0x23d
|
||||
DOMAIN_ALIAS_RID_CERTSVC_DCOM_ACCESS_GROUP = 0x23e
|
||||
)
|
||||
|
||||
//sys LookupAccountSid(systemName *uint16, sid *SID, name *uint16, nameLen *uint32, refdDomainName *uint16, refdDomainNameLen *uint32, use *uint32) (err error) = advapi32.LookupAccountSidW
|
||||
//sys LookupAccountName(systemName *uint16, accountName *uint16, sid *SID, sidLen *uint32, refdDomainName *uint16, refdDomainNameLen *uint32, use *uint32) (err error) = advapi32.LookupAccountNameW
|
||||
//sys ConvertSidToStringSid(sid *SID, stringSid **uint16) (err error) = advapi32.ConvertSidToStringSidW
|
||||
//sys ConvertStringSidToSid(stringSid *uint16, sid **SID) (err error) = advapi32.ConvertStringSidToSidW
|
||||
//sys GetLengthSid(sid *SID) (len uint32) = advapi32.GetLengthSid
|
||||
//sys CopySid(destSidLen uint32, destSid *SID, srcSid *SID) (err error) = advapi32.CopySid
|
||||
//sys AllocateAndInitializeSid(identAuth *SidIdentifierAuthority, subAuth byte, subAuth0 uint32, subAuth1 uint32, subAuth2 uint32, subAuth3 uint32, subAuth4 uint32, subAuth5 uint32, subAuth6 uint32, subAuth7 uint32, sid **SID) (err error) = advapi32.AllocateAndInitializeSid
|
||||
//sys createWellKnownSid(sidType WELL_KNOWN_SID_TYPE, domainSid *SID, sid *SID, sizeSid *uint32) (err error) = advapi32.CreateWellKnownSid
|
||||
//sys isWellKnownSid(sid *SID, sidType WELL_KNOWN_SID_TYPE) (isWellKnown bool) = advapi32.IsWellKnownSid
|
||||
//sys FreeSid(sid *SID) (err error) [failretval!=0] = advapi32.FreeSid
|
||||
//sys EqualSid(sid1 *SID, sid2 *SID) (isEqual bool) = advapi32.EqualSid
|
||||
//sys getSidIdentifierAuthority(sid *SID) (authority *SidIdentifierAuthority) = advapi32.GetSidIdentifierAuthority
|
||||
//sys getSidSubAuthorityCount(sid *SID) (count *uint8) = advapi32.GetSidSubAuthorityCount
|
||||
//sys getSidSubAuthority(sid *SID, index uint32) (subAuthority *uint32) = advapi32.GetSidSubAuthority
|
||||
//sys isValidSid(sid *SID) (isValid bool) = advapi32.IsValidSid
|
||||
|
||||
// The security identifier (SID) structure is a variable-length
|
||||
// structure used to uniquely identify users or groups.
|
||||
type SID struct{}
|
||||
|
||||
// StringToSid converts a string-format security identifier
|
||||
// SID into a valid, functional SID.
|
||||
func StringToSid(s string) (*SID, error) {
|
||||
var sid *SID
|
||||
p, e := UTF16PtrFromString(s)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
e = ConvertStringSidToSid(p, &sid)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
defer LocalFree((Handle)(unsafe.Pointer(sid)))
|
||||
return sid.Copy()
|
||||
}
|
||||
|
||||
// LookupSID retrieves a security identifier SID for the account
|
||||
// and the name of the domain on which the account was found.
|
||||
// System specify target computer to search.
|
||||
func LookupSID(system, account string) (sid *SID, domain string, accType uint32, err error) {
|
||||
if len(account) == 0 {
|
||||
return nil, "", 0, syscall.EINVAL
|
||||
}
|
||||
acc, e := UTF16PtrFromString(account)
|
||||
if e != nil {
|
||||
return nil, "", 0, e
|
||||
}
|
||||
var sys *uint16
|
||||
if len(system) > 0 {
|
||||
sys, e = UTF16PtrFromString(system)
|
||||
if e != nil {
|
||||
return nil, "", 0, e
|
||||
}
|
||||
}
|
||||
n := uint32(50)
|
||||
dn := uint32(50)
|
||||
for {
|
||||
b := make([]byte, n)
|
||||
db := make([]uint16, dn)
|
||||
sid = (*SID)(unsafe.Pointer(&b[0]))
|
||||
e = LookupAccountName(sys, acc, sid, &n, &db[0], &dn, &accType)
|
||||
if e == nil {
|
||||
return sid, UTF16ToString(db), accType, nil
|
||||
}
|
||||
if e != ERROR_INSUFFICIENT_BUFFER {
|
||||
return nil, "", 0, e
|
||||
}
|
||||
if n <= uint32(len(b)) {
|
||||
return nil, "", 0, e
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// String converts SID to a string format
|
||||
// suitable for display, storage, or transmission.
|
||||
func (sid *SID) String() (string, error) {
|
||||
var s *uint16
|
||||
e := ConvertSidToStringSid(sid, &s)
|
||||
if e != nil {
|
||||
return "", e
|
||||
}
|
||||
defer LocalFree((Handle)(unsafe.Pointer(s)))
|
||||
return UTF16ToString((*[256]uint16)(unsafe.Pointer(s))[:]), nil
|
||||
}
|
||||
|
||||
// Len returns the length, in bytes, of a valid security identifier SID.
|
||||
func (sid *SID) Len() int {
|
||||
return int(GetLengthSid(sid))
|
||||
}
|
||||
|
||||
// Copy creates a duplicate of security identifier SID.
|
||||
func (sid *SID) Copy() (*SID, error) {
|
||||
b := make([]byte, sid.Len())
|
||||
sid2 := (*SID)(unsafe.Pointer(&b[0]))
|
||||
e := CopySid(uint32(len(b)), sid2, sid)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
return sid2, nil
|
||||
}
|
||||
|
||||
// IdentifierAuthority returns the identifier authority of the SID.
|
||||
func (sid *SID) IdentifierAuthority() SidIdentifierAuthority {
|
||||
return *getSidIdentifierAuthority(sid)
|
||||
}
|
||||
|
||||
// SubAuthorityCount returns the number of sub-authorities in the SID.
|
||||
func (sid *SID) SubAuthorityCount() uint8 {
|
||||
return *getSidSubAuthorityCount(sid)
|
||||
}
|
||||
|
||||
// SubAuthority returns the sub-authority of the SID as specified by
|
||||
// the index, which must be less than sid.SubAuthorityCount().
|
||||
func (sid *SID) SubAuthority(idx uint32) uint32 {
|
||||
if idx >= uint32(sid.SubAuthorityCount()) {
|
||||
panic("sub-authority index out of range")
|
||||
}
|
||||
return *getSidSubAuthority(sid, idx)
|
||||
}
|
||||
|
||||
// IsValid returns whether the SID has a valid revision and length.
|
||||
func (sid *SID) IsValid() bool {
|
||||
return isValidSid(sid)
|
||||
}
|
||||
|
||||
// Equals compares two SIDs for equality.
|
||||
func (sid *SID) Equals(sid2 *SID) bool {
|
||||
return EqualSid(sid, sid2)
|
||||
}
|
||||
|
||||
// IsWellKnown determines whether the SID matches the well-known sidType.
|
||||
func (sid *SID) IsWellKnown(sidType WELL_KNOWN_SID_TYPE) bool {
|
||||
return isWellKnownSid(sid, sidType)
|
||||
}
|
||||
|
||||
// LookupAccount retrieves the name of the account for this SID
|
||||
// and the name of the first domain on which this SID is found.
|
||||
// System specify target computer to search for.
|
||||
func (sid *SID) LookupAccount(system string) (account, domain string, accType uint32, err error) {
|
||||
var sys *uint16
|
||||
if len(system) > 0 {
|
||||
sys, err = UTF16PtrFromString(system)
|
||||
if err != nil {
|
||||
return "", "", 0, err
|
||||
}
|
||||
}
|
||||
n := uint32(50)
|
||||
dn := uint32(50)
|
||||
for {
|
||||
b := make([]uint16, n)
|
||||
db := make([]uint16, dn)
|
||||
e := LookupAccountSid(sys, sid, &b[0], &n, &db[0], &dn, &accType)
|
||||
if e == nil {
|
||||
return UTF16ToString(b), UTF16ToString(db), accType, nil
|
||||
}
|
||||
if e != ERROR_INSUFFICIENT_BUFFER {
|
||||
return "", "", 0, e
|
||||
}
|
||||
if n <= uint32(len(b)) {
|
||||
return "", "", 0, e
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Various types of pre-specified SIDs that can be synthesized and compared at runtime.
|
||||
type WELL_KNOWN_SID_TYPE uint32
|
||||
|
||||
const (
|
||||
WinNullSid = 0
|
||||
WinWorldSid = 1
|
||||
WinLocalSid = 2
|
||||
WinCreatorOwnerSid = 3
|
||||
WinCreatorGroupSid = 4
|
||||
WinCreatorOwnerServerSid = 5
|
||||
WinCreatorGroupServerSid = 6
|
||||
WinNtAuthoritySid = 7
|
||||
WinDialupSid = 8
|
||||
WinNetworkSid = 9
|
||||
WinBatchSid = 10
|
||||
WinInteractiveSid = 11
|
||||
WinServiceSid = 12
|
||||
WinAnonymousSid = 13
|
||||
WinProxySid = 14
|
||||
WinEnterpriseControllersSid = 15
|
||||
WinSelfSid = 16
|
||||
WinAuthenticatedUserSid = 17
|
||||
WinRestrictedCodeSid = 18
|
||||
WinTerminalServerSid = 19
|
||||
WinRemoteLogonIdSid = 20
|
||||
WinLogonIdsSid = 21
|
||||
WinLocalSystemSid = 22
|
||||
WinLocalServiceSid = 23
|
||||
WinNetworkServiceSid = 24
|
||||
WinBuiltinDomainSid = 25
|
||||
WinBuiltinAdministratorsSid = 26
|
||||
WinBuiltinUsersSid = 27
|
||||
WinBuiltinGuestsSid = 28
|
||||
WinBuiltinPowerUsersSid = 29
|
||||
WinBuiltinAccountOperatorsSid = 30
|
||||
WinBuiltinSystemOperatorsSid = 31
|
||||
WinBuiltinPrintOperatorsSid = 32
|
||||
WinBuiltinBackupOperatorsSid = 33
|
||||
WinBuiltinReplicatorSid = 34
|
||||
WinBuiltinPreWindows2000CompatibleAccessSid = 35
|
||||
WinBuiltinRemoteDesktopUsersSid = 36
|
||||
WinBuiltinNetworkConfigurationOperatorsSid = 37
|
||||
WinAccountAdministratorSid = 38
|
||||
WinAccountGuestSid = 39
|
||||
WinAccountKrbtgtSid = 40
|
||||
WinAccountDomainAdminsSid = 41
|
||||
WinAccountDomainUsersSid = 42
|
||||
WinAccountDomainGuestsSid = 43
|
||||
WinAccountComputersSid = 44
|
||||
WinAccountControllersSid = 45
|
||||
WinAccountCertAdminsSid = 46
|
||||
WinAccountSchemaAdminsSid = 47
|
||||
WinAccountEnterpriseAdminsSid = 48
|
||||
WinAccountPolicyAdminsSid = 49
|
||||
WinAccountRasAndIasServersSid = 50
|
||||
WinNTLMAuthenticationSid = 51
|
||||
WinDigestAuthenticationSid = 52
|
||||
WinSChannelAuthenticationSid = 53
|
||||
WinThisOrganizationSid = 54
|
||||
WinOtherOrganizationSid = 55
|
||||
WinBuiltinIncomingForestTrustBuildersSid = 56
|
||||
WinBuiltinPerfMonitoringUsersSid = 57
|
||||
WinBuiltinPerfLoggingUsersSid = 58
|
||||
WinBuiltinAuthorizationAccessSid = 59
|
||||
WinBuiltinTerminalServerLicenseServersSid = 60
|
||||
WinBuiltinDCOMUsersSid = 61
|
||||
WinBuiltinIUsersSid = 62
|
||||
WinIUserSid = 63
|
||||
WinBuiltinCryptoOperatorsSid = 64
|
||||
WinUntrustedLabelSid = 65
|
||||
WinLowLabelSid = 66
|
||||
WinMediumLabelSid = 67
|
||||
WinHighLabelSid = 68
|
||||
WinSystemLabelSid = 69
|
||||
WinWriteRestrictedCodeSid = 70
|
||||
WinCreatorOwnerRightsSid = 71
|
||||
WinCacheablePrincipalsGroupSid = 72
|
||||
WinNonCacheablePrincipalsGroupSid = 73
|
||||
WinEnterpriseReadonlyControllersSid = 74
|
||||
WinAccountReadonlyControllersSid = 75
|
||||
WinBuiltinEventLogReadersGroup = 76
|
||||
WinNewEnterpriseReadonlyControllersSid = 77
|
||||
WinBuiltinCertSvcDComAccessGroup = 78
|
||||
WinMediumPlusLabelSid = 79
|
||||
WinLocalLogonSid = 80
|
||||
WinConsoleLogonSid = 81
|
||||
WinThisOrganizationCertificateSid = 82
|
||||
WinApplicationPackageAuthoritySid = 83
|
||||
WinBuiltinAnyPackageSid = 84
|
||||
WinCapabilityInternetClientSid = 85
|
||||
WinCapabilityInternetClientServerSid = 86
|
||||
WinCapabilityPrivateNetworkClientServerSid = 87
|
||||
WinCapabilityPicturesLibrarySid = 88
|
||||
WinCapabilityVideosLibrarySid = 89
|
||||
WinCapabilityMusicLibrarySid = 90
|
||||
WinCapabilityDocumentsLibrarySid = 91
|
||||
WinCapabilitySharedUserCertificatesSid = 92
|
||||
WinCapabilityEnterpriseAuthenticationSid = 93
|
||||
WinCapabilityRemovableStorageSid = 94
|
||||
WinBuiltinRDSRemoteAccessServersSid = 95
|
||||
WinBuiltinRDSEndpointServersSid = 96
|
||||
WinBuiltinRDSManagementServersSid = 97
|
||||
WinUserModeDriversSid = 98
|
||||
WinBuiltinHyperVAdminsSid = 99
|
||||
WinAccountCloneableControllersSid = 100
|
||||
WinBuiltinAccessControlAssistanceOperatorsSid = 101
|
||||
WinBuiltinRemoteManagementUsersSid = 102
|
||||
WinAuthenticationAuthorityAssertedSid = 103
|
||||
WinAuthenticationServiceAssertedSid = 104
|
||||
WinLocalAccountSid = 105
|
||||
WinLocalAccountAndAdministratorSid = 106
|
||||
WinAccountProtectedUsersSid = 107
|
||||
WinCapabilityAppointmentsSid = 108
|
||||
WinCapabilityContactsSid = 109
|
||||
WinAccountDefaultSystemManagedSid = 110
|
||||
WinBuiltinDefaultSystemManagedGroupSid = 111
|
||||
WinBuiltinStorageReplicaAdminsSid = 112
|
||||
WinAccountKeyAdminsSid = 113
|
||||
WinAccountEnterpriseKeyAdminsSid = 114
|
||||
WinAuthenticationKeyTrustSid = 115
|
||||
WinAuthenticationKeyPropertyMFASid = 116
|
||||
WinAuthenticationKeyPropertyAttestationSid = 117
|
||||
WinAuthenticationFreshKeyAuthSid = 118
|
||||
WinBuiltinDeviceOwnersSid = 119
|
||||
)
|
||||
|
||||
// Creates a SID for a well-known predefined alias, generally using the constants of the form
|
||||
// Win*Sid, for the local machine.
|
||||
func CreateWellKnownSid(sidType WELL_KNOWN_SID_TYPE) (*SID, error) {
|
||||
return CreateWellKnownDomainSid(sidType, nil)
|
||||
}
|
||||
|
||||
// Creates a SID for a well-known predefined alias, generally using the constants of the form
|
||||
// Win*Sid, for the domain specified by the domainSid parameter.
|
||||
func CreateWellKnownDomainSid(sidType WELL_KNOWN_SID_TYPE, domainSid *SID) (*SID, error) {
|
||||
n := uint32(50)
|
||||
for {
|
||||
b := make([]byte, n)
|
||||
sid := (*SID)(unsafe.Pointer(&b[0]))
|
||||
err := createWellKnownSid(sidType, domainSid, sid, &n)
|
||||
if err == nil {
|
||||
return sid, nil
|
||||
}
|
||||
if err != ERROR_INSUFFICIENT_BUFFER {
|
||||
return nil, err
|
||||
}
|
||||
if n <= uint32(len(b)) {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
// do not reorder
|
||||
TOKEN_ASSIGN_PRIMARY = 1 << iota
|
||||
TOKEN_DUPLICATE
|
||||
TOKEN_IMPERSONATE
|
||||
TOKEN_QUERY
|
||||
TOKEN_QUERY_SOURCE
|
||||
TOKEN_ADJUST_PRIVILEGES
|
||||
TOKEN_ADJUST_GROUPS
|
||||
TOKEN_ADJUST_DEFAULT
|
||||
TOKEN_ADJUST_SESSIONID
|
||||
|
||||
TOKEN_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED |
|
||||
TOKEN_ASSIGN_PRIMARY |
|
||||
TOKEN_DUPLICATE |
|
||||
TOKEN_IMPERSONATE |
|
||||
TOKEN_QUERY |
|
||||
TOKEN_QUERY_SOURCE |
|
||||
TOKEN_ADJUST_PRIVILEGES |
|
||||
TOKEN_ADJUST_GROUPS |
|
||||
TOKEN_ADJUST_DEFAULT |
|
||||
TOKEN_ADJUST_SESSIONID
|
||||
TOKEN_READ = STANDARD_RIGHTS_READ | TOKEN_QUERY
|
||||
TOKEN_WRITE = STANDARD_RIGHTS_WRITE |
|
||||
TOKEN_ADJUST_PRIVILEGES |
|
||||
TOKEN_ADJUST_GROUPS |
|
||||
TOKEN_ADJUST_DEFAULT
|
||||
TOKEN_EXECUTE = STANDARD_RIGHTS_EXECUTE
|
||||
)
|
||||
|
||||
const (
|
||||
// do not reorder
|
||||
TokenUser = 1 + iota
|
||||
TokenGroups
|
||||
TokenPrivileges
|
||||
TokenOwner
|
||||
TokenPrimaryGroup
|
||||
TokenDefaultDacl
|
||||
TokenSource
|
||||
TokenType
|
||||
TokenImpersonationLevel
|
||||
TokenStatistics
|
||||
TokenRestrictedSids
|
||||
TokenSessionId
|
||||
TokenGroupsAndPrivileges
|
||||
TokenSessionReference
|
||||
TokenSandBoxInert
|
||||
TokenAuditPolicy
|
||||
TokenOrigin
|
||||
TokenElevationType
|
||||
TokenLinkedToken
|
||||
TokenElevation
|
||||
TokenHasRestrictions
|
||||
TokenAccessInformation
|
||||
TokenVirtualizationAllowed
|
||||
TokenVirtualizationEnabled
|
||||
TokenIntegrityLevel
|
||||
TokenUIAccess
|
||||
TokenMandatoryPolicy
|
||||
TokenLogonSid
|
||||
MaxTokenInfoClass
|
||||
)
|
||||
|
||||
// Group attributes inside of Tokengroups.Groups[i].Attributes
|
||||
const (
|
||||
SE_GROUP_MANDATORY = 0x00000001
|
||||
SE_GROUP_ENABLED_BY_DEFAULT = 0x00000002
|
||||
SE_GROUP_ENABLED = 0x00000004
|
||||
SE_GROUP_OWNER = 0x00000008
|
||||
SE_GROUP_USE_FOR_DENY_ONLY = 0x00000010
|
||||
SE_GROUP_INTEGRITY = 0x00000020
|
||||
SE_GROUP_INTEGRITY_ENABLED = 0x00000040
|
||||
SE_GROUP_LOGON_ID = 0xC0000000
|
||||
SE_GROUP_RESOURCE = 0x20000000
|
||||
SE_GROUP_VALID_ATTRIBUTES = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED | SE_GROUP_OWNER | SE_GROUP_USE_FOR_DENY_ONLY | SE_GROUP_LOGON_ID | SE_GROUP_RESOURCE | SE_GROUP_INTEGRITY | SE_GROUP_INTEGRITY_ENABLED
|
||||
)
|
||||
|
||||
// Privilege attributes
|
||||
const (
|
||||
SE_PRIVILEGE_ENABLED_BY_DEFAULT = 0x00000001
|
||||
SE_PRIVILEGE_ENABLED = 0x00000002
|
||||
SE_PRIVILEGE_REMOVED = 0x00000004
|
||||
SE_PRIVILEGE_USED_FOR_ACCESS = 0x80000000
|
||||
SE_PRIVILEGE_VALID_ATTRIBUTES = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_REMOVED | SE_PRIVILEGE_USED_FOR_ACCESS
|
||||
)
|
||||
|
||||
// Token types
|
||||
const (
|
||||
TokenPrimary = 1
|
||||
TokenImpersonation = 2
|
||||
)
|
||||
|
||||
// Impersonation levels
|
||||
const (
|
||||
SecurityAnonymous = 0
|
||||
SecurityIdentification = 1
|
||||
SecurityImpersonation = 2
|
||||
SecurityDelegation = 3
|
||||
)
|
||||
|
||||
type LUID struct {
|
||||
LowPart uint32
|
||||
HighPart int32
|
||||
}
|
||||
|
||||
type LUIDAndAttributes struct {
|
||||
Luid LUID
|
||||
Attributes uint32
|
||||
}
|
||||
|
||||
type SIDAndAttributes struct {
|
||||
Sid *SID
|
||||
Attributes uint32
|
||||
}
|
||||
|
||||
type Tokenuser struct {
|
||||
User SIDAndAttributes
|
||||
}
|
||||
|
||||
type Tokenprimarygroup struct {
|
||||
PrimaryGroup *SID
|
||||
}
|
||||
|
||||
type Tokengroups struct {
|
||||
GroupCount uint32
|
||||
Groups [1]SIDAndAttributes // Use AllGroups() for iterating.
|
||||
}
|
||||
|
||||
// AllGroups returns a slice that can be used to iterate over the groups in g.
|
||||
func (g *Tokengroups) AllGroups() []SIDAndAttributes {
|
||||
return (*[(1 << 28) - 1]SIDAndAttributes)(unsafe.Pointer(&g.Groups[0]))[:g.GroupCount:g.GroupCount]
|
||||
}
|
||||
|
||||
type Tokenprivileges struct {
|
||||
PrivilegeCount uint32
|
||||
Privileges [1]LUIDAndAttributes // Use AllPrivileges() for iterating.
|
||||
}
|
||||
|
||||
// AllPrivileges returns a slice that can be used to iterate over the privileges in p.
|
||||
func (p *Tokenprivileges) AllPrivileges() []LUIDAndAttributes {
|
||||
return (*[(1 << 27) - 1]LUIDAndAttributes)(unsafe.Pointer(&p.Privileges[0]))[:p.PrivilegeCount:p.PrivilegeCount]
|
||||
}
|
||||
|
||||
type Tokenmandatorylabel struct {
|
||||
Label SIDAndAttributes
|
||||
}
|
||||
|
||||
func (tml *Tokenmandatorylabel) Size() uint32 {
|
||||
return uint32(unsafe.Sizeof(Tokenmandatorylabel{})) + GetLengthSid(tml.Label.Sid)
|
||||
}
|
||||
|
||||
// Authorization Functions
|
||||
//sys checkTokenMembership(tokenHandle Token, sidToCheck *SID, isMember *int32) (err error) = advapi32.CheckTokenMembership
|
||||
//sys OpenProcessToken(process Handle, access uint32, token *Token) (err error) = advapi32.OpenProcessToken
|
||||
//sys OpenThreadToken(thread Handle, access uint32, openAsSelf bool, token *Token) (err error) = advapi32.OpenThreadToken
|
||||
//sys ImpersonateSelf(impersonationlevel uint32) (err error) = advapi32.ImpersonateSelf
|
||||
//sys RevertToSelf() (err error) = advapi32.RevertToSelf
|
||||
//sys SetThreadToken(thread *Handle, token Token) (err error) = advapi32.SetThreadToken
|
||||
//sys LookupPrivilegeValue(systemname *uint16, name *uint16, luid *LUID) (err error) = advapi32.LookupPrivilegeValueW
|
||||
//sys AdjustTokenPrivileges(token Token, disableAllPrivileges bool, newstate *Tokenprivileges, buflen uint32, prevstate *Tokenprivileges, returnlen *uint32) (err error) = advapi32.AdjustTokenPrivileges
|
||||
//sys AdjustTokenGroups(token Token, resetToDefault bool, newstate *Tokengroups, buflen uint32, prevstate *Tokengroups, returnlen *uint32) (err error) = advapi32.AdjustTokenGroups
|
||||
//sys GetTokenInformation(token Token, infoClass uint32, info *byte, infoLen uint32, returnedLen *uint32) (err error) = advapi32.GetTokenInformation
|
||||
//sys SetTokenInformation(token Token, infoClass uint32, info *byte, infoLen uint32) (err error) = advapi32.SetTokenInformation
|
||||
//sys DuplicateTokenEx(existingToken Token, desiredAccess uint32, tokenAttributes *SecurityAttributes, impersonationLevel uint32, tokenType uint32, newToken *Token) (err error) = advapi32.DuplicateTokenEx
|
||||
//sys GetUserProfileDirectory(t Token, dir *uint16, dirLen *uint32) (err error) = userenv.GetUserProfileDirectoryW
|
||||
//sys getSystemDirectory(dir *uint16, dirLen uint32) (len uint32, err error) = kernel32.GetSystemDirectoryW
|
||||
|
||||
// An access token contains the security information for a logon session.
|
||||
// The system creates an access token when a user logs on, and every
|
||||
// process executed on behalf of the user has a copy of the token.
|
||||
// The token identifies the user, the user's groups, and the user's
|
||||
// privileges. The system uses the token to control access to securable
|
||||
// objects and to control the ability of the user to perform various
|
||||
// system-related operations on the local computer.
|
||||
type Token Handle
|
||||
|
||||
// OpenCurrentProcessToken opens the access token
|
||||
// associated with current process. It is a real
|
||||
// token that needs to be closed, unlike
|
||||
// GetCurrentProcessToken.
|
||||
func OpenCurrentProcessToken() (Token, error) {
|
||||
p, e := GetCurrentProcess()
|
||||
if e != nil {
|
||||
return 0, e
|
||||
}
|
||||
var t Token
|
||||
e = OpenProcessToken(p, TOKEN_QUERY, &t)
|
||||
if e != nil {
|
||||
return 0, e
|
||||
}
|
||||
return t, nil
|
||||
}
|
||||
|
||||
// GetCurrentProcessToken returns the access token associated with
|
||||
// the current process. It is a pseudo token that does not need
|
||||
// to be closed.
|
||||
func GetCurrentProcessToken() Token {
|
||||
return Token(^uintptr(4 - 1))
|
||||
}
|
||||
|
||||
// GetCurrentThreadToken return the access token associated with
|
||||
// the current thread. It is a pseudo token that does not need
|
||||
// to be closed.
|
||||
func GetCurrentThreadToken() Token {
|
||||
return Token(^uintptr(5 - 1))
|
||||
}
|
||||
|
||||
// GetCurrentThreadEffectiveToken returns the effective access token
|
||||
// associated with the current thread. It is a pseudo token that does
|
||||
// not need to be closed.
|
||||
func GetCurrentThreadEffectiveToken() Token {
|
||||
return Token(^uintptr(6 - 1))
|
||||
}
|
||||
|
||||
// Close releases access to access token.
|
||||
func (t Token) Close() error {
|
||||
return CloseHandle(Handle(t))
|
||||
}
|
||||
|
||||
// getInfo retrieves a specified type of information about an access token.
|
||||
func (t Token) getInfo(class uint32, initSize int) (unsafe.Pointer, error) {
|
||||
n := uint32(initSize)
|
||||
for {
|
||||
b := make([]byte, n)
|
||||
e := GetTokenInformation(t, class, &b[0], uint32(len(b)), &n)
|
||||
if e == nil {
|
||||
return unsafe.Pointer(&b[0]), nil
|
||||
}
|
||||
if e != ERROR_INSUFFICIENT_BUFFER {
|
||||
return nil, e
|
||||
}
|
||||
if n <= uint32(len(b)) {
|
||||
return nil, e
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetTokenUser retrieves access token t user account information.
|
||||
func (t Token) GetTokenUser() (*Tokenuser, error) {
|
||||
i, e := t.getInfo(TokenUser, 50)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
return (*Tokenuser)(i), nil
|
||||
}
|
||||
|
||||
// GetTokenGroups retrieves group accounts associated with access token t.
|
||||
func (t Token) GetTokenGroups() (*Tokengroups, error) {
|
||||
i, e := t.getInfo(TokenGroups, 50)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
return (*Tokengroups)(i), nil
|
||||
}
|
||||
|
||||
// GetTokenPrimaryGroup retrieves access token t primary group information.
|
||||
// A pointer to a SID structure representing a group that will become
|
||||
// the primary group of any objects created by a process using this access token.
|
||||
func (t Token) GetTokenPrimaryGroup() (*Tokenprimarygroup, error) {
|
||||
i, e := t.getInfo(TokenPrimaryGroup, 50)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
return (*Tokenprimarygroup)(i), nil
|
||||
}
|
||||
|
||||
// GetUserProfileDirectory retrieves path to the
|
||||
// root directory of the access token t user's profile.
|
||||
func (t Token) GetUserProfileDirectory() (string, error) {
|
||||
n := uint32(100)
|
||||
for {
|
||||
b := make([]uint16, n)
|
||||
e := GetUserProfileDirectory(t, &b[0], &n)
|
||||
if e == nil {
|
||||
return UTF16ToString(b), nil
|
||||
}
|
||||
if e != ERROR_INSUFFICIENT_BUFFER {
|
||||
return "", e
|
||||
}
|
||||
if n <= uint32(len(b)) {
|
||||
return "", e
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// IsElevated returns whether the current token is elevated from a UAC perspective.
|
||||
func (token Token) IsElevated() bool {
|
||||
var isElevated uint32
|
||||
var outLen uint32
|
||||
err := GetTokenInformation(token, TokenElevation, (*byte)(unsafe.Pointer(&isElevated)), uint32(unsafe.Sizeof(isElevated)), &outLen)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return outLen == uint32(unsafe.Sizeof(isElevated)) && isElevated != 0
|
||||
}
|
||||
|
||||
// GetLinkedToken returns the linked token, which may be an elevated UAC token.
|
||||
func (token Token) GetLinkedToken() (Token, error) {
|
||||
var linkedToken Token
|
||||
var outLen uint32
|
||||
err := GetTokenInformation(token, TokenLinkedToken, (*byte)(unsafe.Pointer(&linkedToken)), uint32(unsafe.Sizeof(linkedToken)), &outLen)
|
||||
if err != nil {
|
||||
return Token(0), err
|
||||
}
|
||||
return linkedToken, nil
|
||||
}
|
||||
|
||||
// GetSystemDirectory retrieves path to current location of the system
|
||||
// directory, which is typically, though not always, C:\Windows\System32.
|
||||
func GetSystemDirectory() (string, error) {
|
||||
n := uint32(MAX_PATH)
|
||||
for {
|
||||
b := make([]uint16, n)
|
||||
l, e := getSystemDirectory(&b[0], n)
|
||||
if e != nil {
|
||||
return "", e
|
||||
}
|
||||
if l <= n {
|
||||
return UTF16ToString(b[:l]), nil
|
||||
}
|
||||
n = l
|
||||
}
|
||||
}
|
||||
|
||||
// IsMember reports whether the access token t is a member of the provided SID.
|
||||
func (t Token) IsMember(sid *SID) (bool, error) {
|
||||
var b int32
|
||||
if e := checkTokenMembership(t, sid, &b); e != nil {
|
||||
return false, e
|
||||
}
|
||||
return b != 0, nil
|
||||
}
|
||||
|
||||
const (
|
||||
WTS_CONSOLE_CONNECT = 0x1
|
||||
WTS_CONSOLE_DISCONNECT = 0x2
|
||||
WTS_REMOTE_CONNECT = 0x3
|
||||
WTS_REMOTE_DISCONNECT = 0x4
|
||||
WTS_SESSION_LOGON = 0x5
|
||||
WTS_SESSION_LOGOFF = 0x6
|
||||
WTS_SESSION_LOCK = 0x7
|
||||
WTS_SESSION_UNLOCK = 0x8
|
||||
WTS_SESSION_REMOTE_CONTROL = 0x9
|
||||
WTS_SESSION_CREATE = 0xa
|
||||
WTS_SESSION_TERMINATE = 0xb
|
||||
)
|
||||
|
||||
const (
|
||||
WTSActive = 0
|
||||
WTSConnected = 1
|
||||
WTSConnectQuery = 2
|
||||
WTSShadow = 3
|
||||
WTSDisconnected = 4
|
||||
WTSIdle = 5
|
||||
WTSListen = 6
|
||||
WTSReset = 7
|
||||
WTSDown = 8
|
||||
WTSInit = 9
|
||||
)
|
||||
|
||||
type WTSSESSION_NOTIFICATION struct {
|
||||
Size uint32
|
||||
SessionID uint32
|
||||
}
|
||||
|
||||
type WTS_SESSION_INFO struct {
|
||||
SessionID uint32
|
||||
WindowStationName *uint16
|
||||
State uint32
|
||||
}
|
||||
|
||||
//sys WTSQueryUserToken(session uint32, token *Token) (err error) = wtsapi32.WTSQueryUserToken
|
||||
//sys WTSEnumerateSessions(handle Handle, reserved uint32, version uint32, sessions **WTS_SESSION_INFO, count *uint32) (err error) = wtsapi32.WTSEnumerateSessionsW
|
||||
//sys WTSFreeMemory(ptr uintptr) = wtsapi32.WTSFreeMemory
|
|
@ -0,0 +1,225 @@
|
|||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build windows
|
||||
|
||||
package windows
|
||||
|
||||
const (
|
||||
SC_MANAGER_CONNECT = 1
|
||||
SC_MANAGER_CREATE_SERVICE = 2
|
||||
SC_MANAGER_ENUMERATE_SERVICE = 4
|
||||
SC_MANAGER_LOCK = 8
|
||||
SC_MANAGER_QUERY_LOCK_STATUS = 16
|
||||
SC_MANAGER_MODIFY_BOOT_CONFIG = 32
|
||||
SC_MANAGER_ALL_ACCESS = 0xf003f
|
||||
)
|
||||
|
||||
//sys OpenSCManager(machineName *uint16, databaseName *uint16, access uint32) (handle Handle, err error) [failretval==0] = advapi32.OpenSCManagerW
|
||||
|
||||
const (
|
||||
SERVICE_KERNEL_DRIVER = 1
|
||||
SERVICE_FILE_SYSTEM_DRIVER = 2
|
||||
SERVICE_ADAPTER = 4
|
||||
SERVICE_RECOGNIZER_DRIVER = 8
|
||||
SERVICE_WIN32_OWN_PROCESS = 16
|
||||
SERVICE_WIN32_SHARE_PROCESS = 32
|
||||
SERVICE_WIN32 = SERVICE_WIN32_OWN_PROCESS | SERVICE_WIN32_SHARE_PROCESS
|
||||
SERVICE_INTERACTIVE_PROCESS = 256
|
||||
SERVICE_DRIVER = SERVICE_KERNEL_DRIVER | SERVICE_FILE_SYSTEM_DRIVER | SERVICE_RECOGNIZER_DRIVER
|
||||
SERVICE_TYPE_ALL = SERVICE_WIN32 | SERVICE_ADAPTER | SERVICE_DRIVER | SERVICE_INTERACTIVE_PROCESS
|
||||
|
||||
SERVICE_BOOT_START = 0
|
||||
SERVICE_SYSTEM_START = 1
|
||||
SERVICE_AUTO_START = 2
|
||||
SERVICE_DEMAND_START = 3
|
||||
SERVICE_DISABLED = 4
|
||||
|
||||
SERVICE_ERROR_IGNORE = 0
|
||||
SERVICE_ERROR_NORMAL = 1
|
||||
SERVICE_ERROR_SEVERE = 2
|
||||
SERVICE_ERROR_CRITICAL = 3
|
||||
|
||||
SC_STATUS_PROCESS_INFO = 0
|
||||
|
||||
SC_ACTION_NONE = 0
|
||||
SC_ACTION_RESTART = 1
|
||||
SC_ACTION_REBOOT = 2
|
||||
SC_ACTION_RUN_COMMAND = 3
|
||||
|
||||
SERVICE_STOPPED = 1
|
||||
SERVICE_START_PENDING = 2
|
||||
SERVICE_STOP_PENDING = 3
|
||||
SERVICE_RUNNING = 4
|
||||
SERVICE_CONTINUE_PENDING = 5
|
||||
SERVICE_PAUSE_PENDING = 6
|
||||
SERVICE_PAUSED = 7
|
||||
SERVICE_NO_CHANGE = 0xffffffff
|
||||
|
||||
SERVICE_ACCEPT_STOP = 1
|
||||
SERVICE_ACCEPT_PAUSE_CONTINUE = 2
|
||||
SERVICE_ACCEPT_SHUTDOWN = 4
|
||||
SERVICE_ACCEPT_PARAMCHANGE = 8
|
||||
SERVICE_ACCEPT_NETBINDCHANGE = 16
|
||||
SERVICE_ACCEPT_HARDWAREPROFILECHANGE = 32
|
||||
SERVICE_ACCEPT_POWEREVENT = 64
|
||||
SERVICE_ACCEPT_SESSIONCHANGE = 128
|
||||
|
||||
SERVICE_CONTROL_STOP = 1
|
||||
SERVICE_CONTROL_PAUSE = 2
|
||||
SERVICE_CONTROL_CONTINUE = 3
|
||||
SERVICE_CONTROL_INTERROGATE = 4
|
||||
SERVICE_CONTROL_SHUTDOWN = 5
|
||||
SERVICE_CONTROL_PARAMCHANGE = 6
|
||||
SERVICE_CONTROL_NETBINDADD = 7
|
||||
SERVICE_CONTROL_NETBINDREMOVE = 8
|
||||
SERVICE_CONTROL_NETBINDENABLE = 9
|
||||
SERVICE_CONTROL_NETBINDDISABLE = 10
|
||||
SERVICE_CONTROL_DEVICEEVENT = 11
|
||||
SERVICE_CONTROL_HARDWAREPROFILECHANGE = 12
|
||||
SERVICE_CONTROL_POWEREVENT = 13
|
||||
SERVICE_CONTROL_SESSIONCHANGE = 14
|
||||
|
||||
SERVICE_ACTIVE = 1
|
||||
SERVICE_INACTIVE = 2
|
||||
SERVICE_STATE_ALL = 3
|
||||
|
||||
SERVICE_QUERY_CONFIG = 1
|
||||
SERVICE_CHANGE_CONFIG = 2
|
||||
SERVICE_QUERY_STATUS = 4
|
||||
SERVICE_ENUMERATE_DEPENDENTS = 8
|
||||
SERVICE_START = 16
|
||||
SERVICE_STOP = 32
|
||||
SERVICE_PAUSE_CONTINUE = 64
|
||||
SERVICE_INTERROGATE = 128
|
||||
SERVICE_USER_DEFINED_CONTROL = 256
|
||||
SERVICE_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG | SERVICE_QUERY_STATUS | SERVICE_ENUMERATE_DEPENDENTS | SERVICE_START | SERVICE_STOP | SERVICE_PAUSE_CONTINUE | SERVICE_INTERROGATE | SERVICE_USER_DEFINED_CONTROL
|
||||
|
||||
SERVICE_RUNS_IN_SYSTEM_PROCESS = 1
|
||||
|
||||
SERVICE_CONFIG_DESCRIPTION = 1
|
||||
SERVICE_CONFIG_FAILURE_ACTIONS = 2
|
||||
SERVICE_CONFIG_DELAYED_AUTO_START_INFO = 3
|
||||
SERVICE_CONFIG_FAILURE_ACTIONS_FLAG = 4
|
||||
SERVICE_CONFIG_SERVICE_SID_INFO = 5
|
||||
SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO = 6
|
||||
SERVICE_CONFIG_PRESHUTDOWN_INFO = 7
|
||||
SERVICE_CONFIG_TRIGGER_INFO = 8
|
||||
SERVICE_CONFIG_PREFERRED_NODE = 9
|
||||
SERVICE_CONFIG_LAUNCH_PROTECTED = 12
|
||||
|
||||
SERVICE_SID_TYPE_NONE = 0
|
||||
SERVICE_SID_TYPE_UNRESTRICTED = 1
|
||||
SERVICE_SID_TYPE_RESTRICTED = 2 | SERVICE_SID_TYPE_UNRESTRICTED
|
||||
|
||||
SC_ENUM_PROCESS_INFO = 0
|
||||
|
||||
SERVICE_NOTIFY_STATUS_CHANGE = 2
|
||||
SERVICE_NOTIFY_STOPPED = 0x00000001
|
||||
SERVICE_NOTIFY_START_PENDING = 0x00000002
|
||||
SERVICE_NOTIFY_STOP_PENDING = 0x00000004
|
||||
SERVICE_NOTIFY_RUNNING = 0x00000008
|
||||
SERVICE_NOTIFY_CONTINUE_PENDING = 0x00000010
|
||||
SERVICE_NOTIFY_PAUSE_PENDING = 0x00000020
|
||||
SERVICE_NOTIFY_PAUSED = 0x00000040
|
||||
SERVICE_NOTIFY_CREATED = 0x00000080
|
||||
SERVICE_NOTIFY_DELETED = 0x00000100
|
||||
SERVICE_NOTIFY_DELETE_PENDING = 0x00000200
|
||||
)
|
||||
|
||||
type SERVICE_STATUS struct {
|
||||
ServiceType uint32
|
||||
CurrentState uint32
|
||||
ControlsAccepted uint32
|
||||
Win32ExitCode uint32
|
||||
ServiceSpecificExitCode uint32
|
||||
CheckPoint uint32
|
||||
WaitHint uint32
|
||||
}
|
||||
|
||||
type SERVICE_TABLE_ENTRY struct {
|
||||
ServiceName *uint16
|
||||
ServiceProc uintptr
|
||||
}
|
||||
|
||||
type QUERY_SERVICE_CONFIG struct {
|
||||
ServiceType uint32
|
||||
StartType uint32
|
||||
ErrorControl uint32
|
||||
BinaryPathName *uint16
|
||||
LoadOrderGroup *uint16
|
||||
TagId uint32
|
||||
Dependencies *uint16
|
||||
ServiceStartName *uint16
|
||||
DisplayName *uint16
|
||||
}
|
||||
|
||||
type SERVICE_DESCRIPTION struct {
|
||||
Description *uint16
|
||||
}
|
||||
|
||||
type SERVICE_STATUS_PROCESS struct {
|
||||
ServiceType uint32
|
||||
CurrentState uint32
|
||||
ControlsAccepted uint32
|
||||
Win32ExitCode uint32
|
||||
ServiceSpecificExitCode uint32
|
||||
CheckPoint uint32
|
||||
WaitHint uint32
|
||||
ProcessId uint32
|
||||
ServiceFlags uint32
|
||||
}
|
||||
|
||||
type ENUM_SERVICE_STATUS_PROCESS struct {
|
||||
ServiceName *uint16
|
||||
DisplayName *uint16
|
||||
ServiceStatusProcess SERVICE_STATUS_PROCESS
|
||||
}
|
||||
|
||||
type SERVICE_NOTIFY struct {
|
||||
Version uint32
|
||||
NotifyCallback uintptr
|
||||
Context uintptr
|
||||
NotificationStatus uint32
|
||||
ServiceStatus SERVICE_STATUS_PROCESS
|
||||
NotificationTriggered uint32
|
||||
ServiceNames *uint16
|
||||
}
|
||||
|
||||
type SERVICE_FAILURE_ACTIONS struct {
|
||||
ResetPeriod uint32
|
||||
RebootMsg *uint16
|
||||
Command *uint16
|
||||
ActionsCount uint32
|
||||
Actions *SC_ACTION
|
||||
}
|
||||
|
||||
type SC_ACTION struct {
|
||||
Type uint32
|
||||
Delay uint32
|
||||
}
|
||||
|
||||
type QUERY_SERVICE_LOCK_STATUS struct {
|
||||
IsLocked uint32
|
||||
LockOwner *uint16
|
||||
LockDuration uint32
|
||||
}
|
||||
|
||||
//sys CloseServiceHandle(handle Handle) (err error) = advapi32.CloseServiceHandle
|
||||
//sys CreateService(mgr Handle, serviceName *uint16, displayName *uint16, access uint32, srvType uint32, startType uint32, errCtl uint32, pathName *uint16, loadOrderGroup *uint16, tagId *uint32, dependencies *uint16, serviceStartName *uint16, password *uint16) (handle Handle, err error) [failretval==0] = advapi32.CreateServiceW
|
||||
//sys OpenService(mgr Handle, serviceName *uint16, access uint32) (handle Handle, err error) [failretval==0] = advapi32.OpenServiceW
|
||||
//sys DeleteService(service Handle) (err error) = advapi32.DeleteService
|
||||
//sys StartService(service Handle, numArgs uint32, argVectors **uint16) (err error) = advapi32.StartServiceW
|
||||
//sys QueryServiceStatus(service Handle, status *SERVICE_STATUS) (err error) = advapi32.QueryServiceStatus
|
||||
//sys QueryServiceLockStatus(mgr Handle, lockStatus *QUERY_SERVICE_LOCK_STATUS, bufSize uint32, bytesNeeded *uint32) (err error) = advapi32.QueryServiceLockStatusW
|
||||
//sys ControlService(service Handle, control uint32, status *SERVICE_STATUS) (err error) = advapi32.ControlService
|
||||
//sys StartServiceCtrlDispatcher(serviceTable *SERVICE_TABLE_ENTRY) (err error) = advapi32.StartServiceCtrlDispatcherW
|
||||
//sys SetServiceStatus(service Handle, serviceStatus *SERVICE_STATUS) (err error) = advapi32.SetServiceStatus
|
||||
//sys ChangeServiceConfig(service Handle, serviceType uint32, startType uint32, errorControl uint32, binaryPathName *uint16, loadOrderGroup *uint16, tagId *uint32, dependencies *uint16, serviceStartName *uint16, password *uint16, displayName *uint16) (err error) = advapi32.ChangeServiceConfigW
|
||||
//sys QueryServiceConfig(service Handle, serviceConfig *QUERY_SERVICE_CONFIG, bufSize uint32, bytesNeeded *uint32) (err error) = advapi32.QueryServiceConfigW
|
||||
//sys ChangeServiceConfig2(service Handle, infoLevel uint32, info *byte) (err error) = advapi32.ChangeServiceConfig2W
|
||||
//sys QueryServiceConfig2(service Handle, infoLevel uint32, buff *byte, buffSize uint32, bytesNeeded *uint32) (err error) = advapi32.QueryServiceConfig2W
|
||||
//sys EnumServicesStatusEx(mgr Handle, infoLevel uint32, serviceType uint32, serviceState uint32, services *byte, bufSize uint32, bytesNeeded *uint32, servicesReturned *uint32, resumeHandle *uint32, groupName *uint16) (err error) = advapi32.EnumServicesStatusExW
|
||||
//sys QueryServiceStatusEx(service Handle, infoLevel uint32, buff *byte, buffSize uint32, bytesNeeded *uint32) (err error) = advapi32.QueryServiceStatusEx
|
||||
//sys NotifyServiceStatusChange(service Handle, notifyMask uint32, notifier *SERVICE_NOTIFY) (ret error) = advapi32.NotifyServiceStatusChangeW
|
|
@ -0,0 +1,22 @@
|
|||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build windows
|
||||
|
||||
package windows
|
||||
|
||||
func itoa(val int) string { // do it here rather than with fmt to avoid dependency
|
||||
if val < 0 {
|
||||
return "-" + itoa(-val)
|
||||
}
|
||||
var buf [32]byte // big enough for int64
|
||||
i := len(buf) - 1
|
||||
for val >= 10 {
|
||||
buf[i] = byte(val%10 + '0')
|
||||
i--
|
||||
val /= 10
|
||||
}
|
||||
buf[i] = byte(val + '0')
|
||||
return string(buf[i:])
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build windows
|
||||
|
||||
// Package windows contains an interface to the low-level operating system
|
||||
// primitives. OS details vary depending on the underlying system, and
|
||||
// by default, godoc will display the OS-specific documentation for the current
|
||||
// system. If you want godoc to display syscall documentation for another
|
||||
// system, set $GOOS and $GOARCH to the desired system. For example, if
|
||||
// you want to view documentation for freebsd/arm on linux/amd64, set $GOOS
|
||||
// to freebsd and $GOARCH to arm.
|
||||
//
|
||||
// The primary use of this package is inside other packages that provide a more
|
||||
// portable interface to the system, such as "os", "time" and "net". Use
|
||||
// those packages rather than this one if you can.
|
||||
//
|
||||
// For details of the functions and data types in this package consult
|
||||
// the manuals for the appropriate operating system.
|
||||
//
|
||||
// These calls return err == nil to indicate success; otherwise
|
||||
// err represents an operating system error describing the failure and
|
||||
// holds a value of type syscall.Errno.
|
||||
package windows // import "golang.org/x/sys/windows"
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// ByteSliceFromString returns a NUL-terminated slice of bytes
|
||||
// containing the text of s. If s contains a NUL byte at any
|
||||
// location, it returns (nil, syscall.EINVAL).
|
||||
func ByteSliceFromString(s string) ([]byte, error) {
|
||||
for i := 0; i < len(s); i++ {
|
||||
if s[i] == 0 {
|
||||
return nil, syscall.EINVAL
|
||||
}
|
||||
}
|
||||
a := make([]byte, len(s)+1)
|
||||
copy(a, s)
|
||||
return a, nil
|
||||
}
|
||||
|
||||
// BytePtrFromString returns a pointer to a NUL-terminated array of
|
||||
// bytes containing the text of s. If s contains a NUL byte at any
|
||||
// location, it returns (nil, syscall.EINVAL).
|
||||
func BytePtrFromString(s string) (*byte, error) {
|
||||
a, err := ByteSliceFromString(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &a[0], nil
|
||||
}
|
||||
|
||||
// Single-word zero for use when we need a valid pointer to 0 bytes.
|
||||
// See mksyscall.pl.
|
||||
var _zero uintptr
|
||||
|
||||
func (ts *Timespec) Unix() (sec int64, nsec int64) {
|
||||
return int64(ts.Sec), int64(ts.Nsec)
|
||||
}
|
||||
|
||||
func (tv *Timeval) Unix() (sec int64, nsec int64) {
|
||||
return int64(tv.Sec), int64(tv.Usec) * 1000
|
||||
}
|
||||
|
||||
func (ts *Timespec) Nano() int64 {
|
||||
return int64(ts.Sec)*1e9 + int64(ts.Nsec)
|
||||
}
|
||||
|
||||
func (tv *Timeval) Nano() int64 {
|
||||
return int64(tv.Sec)*1e9 + int64(tv.Usec)*1000
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,22 @@
|
|||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package windows
|
||||
|
||||
type WSAData struct {
|
||||
Version uint16
|
||||
HighVersion uint16
|
||||
Description [WSADESCRIPTION_LEN + 1]byte
|
||||
SystemStatus [WSASYS_STATUS_LEN + 1]byte
|
||||
MaxSockets uint16
|
||||
MaxUdpDg uint16
|
||||
VendorInfo *byte
|
||||
}
|
||||
|
||||
type Servent struct {
|
||||
Name *byte
|
||||
Aliases **byte
|
||||
Port uint16
|
||||
Proto *byte
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package windows
|
||||
|
||||
type WSAData struct {
|
||||
Version uint16
|
||||
HighVersion uint16
|
||||
MaxSockets uint16
|
||||
MaxUdpDg uint16
|
||||
VendorInfo *byte
|
||||
Description [WSADESCRIPTION_LEN + 1]byte
|
||||
SystemStatus [WSASYS_STATUS_LEN + 1]byte
|
||||
}
|
||||
|
||||
type Servent struct {
|
||||
Name *byte
|
||||
Aliases **byte
|
||||
Proto *byte
|
||||
Port uint16
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package windows
|
||||
|
||||
type WSAData struct {
|
||||
Version uint16
|
||||
HighVersion uint16
|
||||
Description [WSADESCRIPTION_LEN + 1]byte
|
||||
SystemStatus [WSASYS_STATUS_LEN + 1]byte
|
||||
MaxSockets uint16
|
||||
MaxUdpDg uint16
|
||||
VendorInfo *byte
|
||||
}
|
||||
|
||||
type Servent struct {
|
||||
Name *byte
|
||||
Aliases **byte
|
||||
Port uint16
|
||||
Proto *byte
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,149 @@
|
|||
// Code generated by 'mkknownfolderids.bash'; DO NOT EDIT.
|
||||
|
||||
package windows
|
||||
|
||||
type KNOWNFOLDERID GUID
|
||||
|
||||
var (
|
||||
FOLDERID_NetworkFolder = &KNOWNFOLDERID{0xd20beec4, 0x5ca8, 0x4905, [8]byte{0xae, 0x3b, 0xbf, 0x25, 0x1e, 0xa0, 0x9b, 0x53}}
|
||||
FOLDERID_ComputerFolder = &KNOWNFOLDERID{0x0ac0837c, 0xbbf8, 0x452a, [8]byte{0x85, 0x0d, 0x79, 0xd0, 0x8e, 0x66, 0x7c, 0xa7}}
|
||||
FOLDERID_InternetFolder = &KNOWNFOLDERID{0x4d9f7874, 0x4e0c, 0x4904, [8]byte{0x96, 0x7b, 0x40, 0xb0, 0xd2, 0x0c, 0x3e, 0x4b}}
|
||||
FOLDERID_ControlPanelFolder = &KNOWNFOLDERID{0x82a74aeb, 0xaeb4, 0x465c, [8]byte{0xa0, 0x14, 0xd0, 0x97, 0xee, 0x34, 0x6d, 0x63}}
|
||||
FOLDERID_PrintersFolder = &KNOWNFOLDERID{0x76fc4e2d, 0xd6ad, 0x4519, [8]byte{0xa6, 0x63, 0x37, 0xbd, 0x56, 0x06, 0x81, 0x85}}
|
||||
FOLDERID_SyncManagerFolder = &KNOWNFOLDERID{0x43668bf8, 0xc14e, 0x49b2, [8]byte{0x97, 0xc9, 0x74, 0x77, 0x84, 0xd7, 0x84, 0xb7}}
|
||||
FOLDERID_SyncSetupFolder = &KNOWNFOLDERID{0x0f214138, 0xb1d3, 0x4a90, [8]byte{0xbb, 0xa9, 0x27, 0xcb, 0xc0, 0xc5, 0x38, 0x9a}}
|
||||
FOLDERID_ConflictFolder = &KNOWNFOLDERID{0x4bfefb45, 0x347d, 0x4006, [8]byte{0xa5, 0xbe, 0xac, 0x0c, 0xb0, 0x56, 0x71, 0x92}}
|
||||
FOLDERID_SyncResultsFolder = &KNOWNFOLDERID{0x289a9a43, 0xbe44, 0x4057, [8]byte{0xa4, 0x1b, 0x58, 0x7a, 0x76, 0xd7, 0xe7, 0xf9}}
|
||||
FOLDERID_RecycleBinFolder = &KNOWNFOLDERID{0xb7534046, 0x3ecb, 0x4c18, [8]byte{0xbe, 0x4e, 0x64, 0xcd, 0x4c, 0xb7, 0xd6, 0xac}}
|
||||
FOLDERID_ConnectionsFolder = &KNOWNFOLDERID{0x6f0cd92b, 0x2e97, 0x45d1, [8]byte{0x88, 0xff, 0xb0, 0xd1, 0x86, 0xb8, 0xde, 0xdd}}
|
||||
FOLDERID_Fonts = &KNOWNFOLDERID{0xfd228cb7, 0xae11, 0x4ae3, [8]byte{0x86, 0x4c, 0x16, 0xf3, 0x91, 0x0a, 0xb8, 0xfe}}
|
||||
FOLDERID_Desktop = &KNOWNFOLDERID{0xb4bfcc3a, 0xdb2c, 0x424c, [8]byte{0xb0, 0x29, 0x7f, 0xe9, 0x9a, 0x87, 0xc6, 0x41}}
|
||||
FOLDERID_Startup = &KNOWNFOLDERID{0xb97d20bb, 0xf46a, 0x4c97, [8]byte{0xba, 0x10, 0x5e, 0x36, 0x08, 0x43, 0x08, 0x54}}
|
||||
FOLDERID_Programs = &KNOWNFOLDERID{0xa77f5d77, 0x2e2b, 0x44c3, [8]byte{0xa6, 0xa2, 0xab, 0xa6, 0x01, 0x05, 0x4a, 0x51}}
|
||||
FOLDERID_StartMenu = &KNOWNFOLDERID{0x625b53c3, 0xab48, 0x4ec1, [8]byte{0xba, 0x1f, 0xa1, 0xef, 0x41, 0x46, 0xfc, 0x19}}
|
||||
FOLDERID_Recent = &KNOWNFOLDERID{0xae50c081, 0xebd2, 0x438a, [8]byte{0x86, 0x55, 0x8a, 0x09, 0x2e, 0x34, 0x98, 0x7a}}
|
||||
FOLDERID_SendTo = &KNOWNFOLDERID{0x8983036c, 0x27c0, 0x404b, [8]byte{0x8f, 0x08, 0x10, 0x2d, 0x10, 0xdc, 0xfd, 0x74}}
|
||||
FOLDERID_Documents = &KNOWNFOLDERID{0xfdd39ad0, 0x238f, 0x46af, [8]byte{0xad, 0xb4, 0x6c, 0x85, 0x48, 0x03, 0x69, 0xc7}}
|
||||
FOLDERID_Favorites = &KNOWNFOLDERID{0x1777f761, 0x68ad, 0x4d8a, [8]byte{0x87, 0xbd, 0x30, 0xb7, 0x59, 0xfa, 0x33, 0xdd}}
|
||||
FOLDERID_NetHood = &KNOWNFOLDERID{0xc5abbf53, 0xe17f, 0x4121, [8]byte{0x89, 0x00, 0x86, 0x62, 0x6f, 0xc2, 0xc9, 0x73}}
|
||||
FOLDERID_PrintHood = &KNOWNFOLDERID{0x9274bd8d, 0xcfd1, 0x41c3, [8]byte{0xb3, 0x5e, 0xb1, 0x3f, 0x55, 0xa7, 0x58, 0xf4}}
|
||||
FOLDERID_Templates = &KNOWNFOLDERID{0xa63293e8, 0x664e, 0x48db, [8]byte{0xa0, 0x79, 0xdf, 0x75, 0x9e, 0x05, 0x09, 0xf7}}
|
||||
FOLDERID_CommonStartup = &KNOWNFOLDERID{0x82a5ea35, 0xd9cd, 0x47c5, [8]byte{0x96, 0x29, 0xe1, 0x5d, 0x2f, 0x71, 0x4e, 0x6e}}
|
||||
FOLDERID_CommonPrograms = &KNOWNFOLDERID{0x0139d44e, 0x6afe, 0x49f2, [8]byte{0x86, 0x90, 0x3d, 0xaf, 0xca, 0xe6, 0xff, 0xb8}}
|
||||
FOLDERID_CommonStartMenu = &KNOWNFOLDERID{0xa4115719, 0xd62e, 0x491d, [8]byte{0xaa, 0x7c, 0xe7, 0x4b, 0x8b, 0xe3, 0xb0, 0x67}}
|
||||
FOLDERID_PublicDesktop = &KNOWNFOLDERID{0xc4aa340d, 0xf20f, 0x4863, [8]byte{0xaf, 0xef, 0xf8, 0x7e, 0xf2, 0xe6, 0xba, 0x25}}
|
||||
FOLDERID_ProgramData = &KNOWNFOLDERID{0x62ab5d82, 0xfdc1, 0x4dc3, [8]byte{0xa9, 0xdd, 0x07, 0x0d, 0x1d, 0x49, 0x5d, 0x97}}
|
||||
FOLDERID_CommonTemplates = &KNOWNFOLDERID{0xb94237e7, 0x57ac, 0x4347, [8]byte{0x91, 0x51, 0xb0, 0x8c, 0x6c, 0x32, 0xd1, 0xf7}}
|
||||
FOLDERID_PublicDocuments = &KNOWNFOLDERID{0xed4824af, 0xdce4, 0x45a8, [8]byte{0x81, 0xe2, 0xfc, 0x79, 0x65, 0x08, 0x36, 0x34}}
|
||||
FOLDERID_RoamingAppData = &KNOWNFOLDERID{0x3eb685db, 0x65f9, 0x4cf6, [8]byte{0xa0, 0x3a, 0xe3, 0xef, 0x65, 0x72, 0x9f, 0x3d}}
|
||||
FOLDERID_LocalAppData = &KNOWNFOLDERID{0xf1b32785, 0x6fba, 0x4fcf, [8]byte{0x9d, 0x55, 0x7b, 0x8e, 0x7f, 0x15, 0x70, 0x91}}
|
||||
FOLDERID_LocalAppDataLow = &KNOWNFOLDERID{0xa520a1a4, 0x1780, 0x4ff6, [8]byte{0xbd, 0x18, 0x16, 0x73, 0x43, 0xc5, 0xaf, 0x16}}
|
||||
FOLDERID_InternetCache = &KNOWNFOLDERID{0x352481e8, 0x33be, 0x4251, [8]byte{0xba, 0x85, 0x60, 0x07, 0xca, 0xed, 0xcf, 0x9d}}
|
||||
FOLDERID_Cookies = &KNOWNFOLDERID{0x2b0f765d, 0xc0e9, 0x4171, [8]byte{0x90, 0x8e, 0x08, 0xa6, 0x11, 0xb8, 0x4f, 0xf6}}
|
||||
FOLDERID_History = &KNOWNFOLDERID{0xd9dc8a3b, 0xb784, 0x432e, [8]byte{0xa7, 0x81, 0x5a, 0x11, 0x30, 0xa7, 0x59, 0x63}}
|
||||
FOLDERID_System = &KNOWNFOLDERID{0x1ac14e77, 0x02e7, 0x4e5d, [8]byte{0xb7, 0x44, 0x2e, 0xb1, 0xae, 0x51, 0x98, 0xb7}}
|
||||
FOLDERID_SystemX86 = &KNOWNFOLDERID{0xd65231b0, 0xb2f1, 0x4857, [8]byte{0xa4, 0xce, 0xa8, 0xe7, 0xc6, 0xea, 0x7d, 0x27}}
|
||||
FOLDERID_Windows = &KNOWNFOLDERID{0xf38bf404, 0x1d43, 0x42f2, [8]byte{0x93, 0x05, 0x67, 0xde, 0x0b, 0x28, 0xfc, 0x23}}
|
||||
FOLDERID_Profile = &KNOWNFOLDERID{0x5e6c858f, 0x0e22, 0x4760, [8]byte{0x9a, 0xfe, 0xea, 0x33, 0x17, 0xb6, 0x71, 0x73}}
|
||||
FOLDERID_Pictures = &KNOWNFOLDERID{0x33e28130, 0x4e1e, 0x4676, [8]byte{0x83, 0x5a, 0x98, 0x39, 0x5c, 0x3b, 0xc3, 0xbb}}
|
||||
FOLDERID_ProgramFilesX86 = &KNOWNFOLDERID{0x7c5a40ef, 0xa0fb, 0x4bfc, [8]byte{0x87, 0x4a, 0xc0, 0xf2, 0xe0, 0xb9, 0xfa, 0x8e}}
|
||||
FOLDERID_ProgramFilesCommonX86 = &KNOWNFOLDERID{0xde974d24, 0xd9c6, 0x4d3e, [8]byte{0xbf, 0x91, 0xf4, 0x45, 0x51, 0x20, 0xb9, 0x17}}
|
||||
FOLDERID_ProgramFilesX64 = &KNOWNFOLDERID{0x6d809377, 0x6af0, 0x444b, [8]byte{0x89, 0x57, 0xa3, 0x77, 0x3f, 0x02, 0x20, 0x0e}}
|
||||
FOLDERID_ProgramFilesCommonX64 = &KNOWNFOLDERID{0x6365d5a7, 0x0f0d, 0x45e5, [8]byte{0x87, 0xf6, 0x0d, 0xa5, 0x6b, 0x6a, 0x4f, 0x7d}}
|
||||
FOLDERID_ProgramFiles = &KNOWNFOLDERID{0x905e63b6, 0xc1bf, 0x494e, [8]byte{0xb2, 0x9c, 0x65, 0xb7, 0x32, 0xd3, 0xd2, 0x1a}}
|
||||
FOLDERID_ProgramFilesCommon = &KNOWNFOLDERID{0xf7f1ed05, 0x9f6d, 0x47a2, [8]byte{0xaa, 0xae, 0x29, 0xd3, 0x17, 0xc6, 0xf0, 0x66}}
|
||||
FOLDERID_UserProgramFiles = &KNOWNFOLDERID{0x5cd7aee2, 0x2219, 0x4a67, [8]byte{0xb8, 0x5d, 0x6c, 0x9c, 0xe1, 0x56, 0x60, 0xcb}}
|
||||
FOLDERID_UserProgramFilesCommon = &KNOWNFOLDERID{0xbcbd3057, 0xca5c, 0x4622, [8]byte{0xb4, 0x2d, 0xbc, 0x56, 0xdb, 0x0a, 0xe5, 0x16}}
|
||||
FOLDERID_AdminTools = &KNOWNFOLDERID{0x724ef170, 0xa42d, 0x4fef, [8]byte{0x9f, 0x26, 0xb6, 0x0e, 0x84, 0x6f, 0xba, 0x4f}}
|
||||
FOLDERID_CommonAdminTools = &KNOWNFOLDERID{0xd0384e7d, 0xbac3, 0x4797, [8]byte{0x8f, 0x14, 0xcb, 0xa2, 0x29, 0xb3, 0x92, 0xb5}}
|
||||
FOLDERID_Music = &KNOWNFOLDERID{0x4bd8d571, 0x6d19, 0x48d3, [8]byte{0xbe, 0x97, 0x42, 0x22, 0x20, 0x08, 0x0e, 0x43}}
|
||||
FOLDERID_Videos = &KNOWNFOLDERID{0x18989b1d, 0x99b5, 0x455b, [8]byte{0x84, 0x1c, 0xab, 0x7c, 0x74, 0xe4, 0xdd, 0xfc}}
|
||||
FOLDERID_Ringtones = &KNOWNFOLDERID{0xc870044b, 0xf49e, 0x4126, [8]byte{0xa9, 0xc3, 0xb5, 0x2a, 0x1f, 0xf4, 0x11, 0xe8}}
|
||||
FOLDERID_PublicPictures = &KNOWNFOLDERID{0xb6ebfb86, 0x6907, 0x413c, [8]byte{0x9a, 0xf7, 0x4f, 0xc2, 0xab, 0xf0, 0x7c, 0xc5}}
|
||||
FOLDERID_PublicMusic = &KNOWNFOLDERID{0x3214fab5, 0x9757, 0x4298, [8]byte{0xbb, 0x61, 0x92, 0xa9, 0xde, 0xaa, 0x44, 0xff}}
|
||||
FOLDERID_PublicVideos = &KNOWNFOLDERID{0x2400183a, 0x6185, 0x49fb, [8]byte{0xa2, 0xd8, 0x4a, 0x39, 0x2a, 0x60, 0x2b, 0xa3}}
|
||||
FOLDERID_PublicRingtones = &KNOWNFOLDERID{0xe555ab60, 0x153b, 0x4d17, [8]byte{0x9f, 0x04, 0xa5, 0xfe, 0x99, 0xfc, 0x15, 0xec}}
|
||||
FOLDERID_ResourceDir = &KNOWNFOLDERID{0x8ad10c31, 0x2adb, 0x4296, [8]byte{0xa8, 0xf7, 0xe4, 0x70, 0x12, 0x32, 0xc9, 0x72}}
|
||||
FOLDERID_LocalizedResourcesDir = &KNOWNFOLDERID{0x2a00375e, 0x224c, 0x49de, [8]byte{0xb8, 0xd1, 0x44, 0x0d, 0xf7, 0xef, 0x3d, 0xdc}}
|
||||
FOLDERID_CommonOEMLinks = &KNOWNFOLDERID{0xc1bae2d0, 0x10df, 0x4334, [8]byte{0xbe, 0xdd, 0x7a, 0xa2, 0x0b, 0x22, 0x7a, 0x9d}}
|
||||
FOLDERID_CDBurning = &KNOWNFOLDERID{0x9e52ab10, 0xf80d, 0x49df, [8]byte{0xac, 0xb8, 0x43, 0x30, 0xf5, 0x68, 0x78, 0x55}}
|
||||
FOLDERID_UserProfiles = &KNOWNFOLDERID{0x0762d272, 0xc50a, 0x4bb0, [8]byte{0xa3, 0x82, 0x69, 0x7d, 0xcd, 0x72, 0x9b, 0x80}}
|
||||
FOLDERID_Playlists = &KNOWNFOLDERID{0xde92c1c7, 0x837f, 0x4f69, [8]byte{0xa3, 0xbb, 0x86, 0xe6, 0x31, 0x20, 0x4a, 0x23}}
|
||||
FOLDERID_SamplePlaylists = &KNOWNFOLDERID{0x15ca69b3, 0x30ee, 0x49c1, [8]byte{0xac, 0xe1, 0x6b, 0x5e, 0xc3, 0x72, 0xaf, 0xb5}}
|
||||
FOLDERID_SampleMusic = &KNOWNFOLDERID{0xb250c668, 0xf57d, 0x4ee1, [8]byte{0xa6, 0x3c, 0x29, 0x0e, 0xe7, 0xd1, 0xaa, 0x1f}}
|
||||
FOLDERID_SamplePictures = &KNOWNFOLDERID{0xc4900540, 0x2379, 0x4c75, [8]byte{0x84, 0x4b, 0x64, 0xe6, 0xfa, 0xf8, 0x71, 0x6b}}
|
||||
FOLDERID_SampleVideos = &KNOWNFOLDERID{0x859ead94, 0x2e85, 0x48ad, [8]byte{0xa7, 0x1a, 0x09, 0x69, 0xcb, 0x56, 0xa6, 0xcd}}
|
||||
FOLDERID_PhotoAlbums = &KNOWNFOLDERID{0x69d2cf90, 0xfc33, 0x4fb7, [8]byte{0x9a, 0x0c, 0xeb, 0xb0, 0xf0, 0xfc, 0xb4, 0x3c}}
|
||||
FOLDERID_Public = &KNOWNFOLDERID{0xdfdf76a2, 0xc82a, 0x4d63, [8]byte{0x90, 0x6a, 0x56, 0x44, 0xac, 0x45, 0x73, 0x85}}
|
||||
FOLDERID_ChangeRemovePrograms = &KNOWNFOLDERID{0xdf7266ac, 0x9274, 0x4867, [8]byte{0x8d, 0x55, 0x3b, 0xd6, 0x61, 0xde, 0x87, 0x2d}}
|
||||
FOLDERID_AppUpdates = &KNOWNFOLDERID{0xa305ce99, 0xf527, 0x492b, [8]byte{0x8b, 0x1a, 0x7e, 0x76, 0xfa, 0x98, 0xd6, 0xe4}}
|
||||
FOLDERID_AddNewPrograms = &KNOWNFOLDERID{0xde61d971, 0x5ebc, 0x4f02, [8]byte{0xa3, 0xa9, 0x6c, 0x82, 0x89, 0x5e, 0x5c, 0x04}}
|
||||
FOLDERID_Downloads = &KNOWNFOLDERID{0x374de290, 0x123f, 0x4565, [8]byte{0x91, 0x64, 0x39, 0xc4, 0x92, 0x5e, 0x46, 0x7b}}
|
||||
FOLDERID_PublicDownloads = &KNOWNFOLDERID{0x3d644c9b, 0x1fb8, 0x4f30, [8]byte{0x9b, 0x45, 0xf6, 0x70, 0x23, 0x5f, 0x79, 0xc0}}
|
||||
FOLDERID_SavedSearches = &KNOWNFOLDERID{0x7d1d3a04, 0xdebb, 0x4115, [8]byte{0x95, 0xcf, 0x2f, 0x29, 0xda, 0x29, 0x20, 0xda}}
|
||||
FOLDERID_QuickLaunch = &KNOWNFOLDERID{0x52a4f021, 0x7b75, 0x48a9, [8]byte{0x9f, 0x6b, 0x4b, 0x87, 0xa2, 0x10, 0xbc, 0x8f}}
|
||||
FOLDERID_Contacts = &KNOWNFOLDERID{0x56784854, 0xc6cb, 0x462b, [8]byte{0x81, 0x69, 0x88, 0xe3, 0x50, 0xac, 0xb8, 0x82}}
|
||||
FOLDERID_SidebarParts = &KNOWNFOLDERID{0xa75d362e, 0x50fc, 0x4fb7, [8]byte{0xac, 0x2c, 0xa8, 0xbe, 0xaa, 0x31, 0x44, 0x93}}
|
||||
FOLDERID_SidebarDefaultParts = &KNOWNFOLDERID{0x7b396e54, 0x9ec5, 0x4300, [8]byte{0xbe, 0x0a, 0x24, 0x82, 0xeb, 0xae, 0x1a, 0x26}}
|
||||
FOLDERID_PublicGameTasks = &KNOWNFOLDERID{0xdebf2536, 0xe1a8, 0x4c59, [8]byte{0xb6, 0xa2, 0x41, 0x45, 0x86, 0x47, 0x6a, 0xea}}
|
||||
FOLDERID_GameTasks = &KNOWNFOLDERID{0x054fae61, 0x4dd8, 0x4787, [8]byte{0x80, 0xb6, 0x09, 0x02, 0x20, 0xc4, 0xb7, 0x00}}
|
||||
FOLDERID_SavedGames = &KNOWNFOLDERID{0x4c5c32ff, 0xbb9d, 0x43b0, [8]byte{0xb5, 0xb4, 0x2d, 0x72, 0xe5, 0x4e, 0xaa, 0xa4}}
|
||||
FOLDERID_Games = &KNOWNFOLDERID{0xcac52c1a, 0xb53d, 0x4edc, [8]byte{0x92, 0xd7, 0x6b, 0x2e, 0x8a, 0xc1, 0x94, 0x34}}
|
||||
FOLDERID_SEARCH_MAPI = &KNOWNFOLDERID{0x98ec0e18, 0x2098, 0x4d44, [8]byte{0x86, 0x44, 0x66, 0x97, 0x93, 0x15, 0xa2, 0x81}}
|
||||
FOLDERID_SEARCH_CSC = &KNOWNFOLDERID{0xee32e446, 0x31ca, 0x4aba, [8]byte{0x81, 0x4f, 0xa5, 0xeb, 0xd2, 0xfd, 0x6d, 0x5e}}
|
||||
FOLDERID_Links = &KNOWNFOLDERID{0xbfb9d5e0, 0xc6a9, 0x404c, [8]byte{0xb2, 0xb2, 0xae, 0x6d, 0xb6, 0xaf, 0x49, 0x68}}
|
||||
FOLDERID_UsersFiles = &KNOWNFOLDERID{0xf3ce0f7c, 0x4901, 0x4acc, [8]byte{0x86, 0x48, 0xd5, 0xd4, 0x4b, 0x04, 0xef, 0x8f}}
|
||||
FOLDERID_UsersLibraries = &KNOWNFOLDERID{0xa302545d, 0xdeff, 0x464b, [8]byte{0xab, 0xe8, 0x61, 0xc8, 0x64, 0x8d, 0x93, 0x9b}}
|
||||
FOLDERID_SearchHome = &KNOWNFOLDERID{0x190337d1, 0xb8ca, 0x4121, [8]byte{0xa6, 0x39, 0x6d, 0x47, 0x2d, 0x16, 0x97, 0x2a}}
|
||||
FOLDERID_OriginalImages = &KNOWNFOLDERID{0x2c36c0aa, 0x5812, 0x4b87, [8]byte{0xbf, 0xd0, 0x4c, 0xd0, 0xdf, 0xb1, 0x9b, 0x39}}
|
||||
FOLDERID_DocumentsLibrary = &KNOWNFOLDERID{0x7b0db17d, 0x9cd2, 0x4a93, [8]byte{0x97, 0x33, 0x46, 0xcc, 0x89, 0x02, 0x2e, 0x7c}}
|
||||
FOLDERID_MusicLibrary = &KNOWNFOLDERID{0x2112ab0a, 0xc86a, 0x4ffe, [8]byte{0xa3, 0x68, 0x0d, 0xe9, 0x6e, 0x47, 0x01, 0x2e}}
|
||||
FOLDERID_PicturesLibrary = &KNOWNFOLDERID{0xa990ae9f, 0xa03b, 0x4e80, [8]byte{0x94, 0xbc, 0x99, 0x12, 0xd7, 0x50, 0x41, 0x04}}
|
||||
FOLDERID_VideosLibrary = &KNOWNFOLDERID{0x491e922f, 0x5643, 0x4af4, [8]byte{0xa7, 0xeb, 0x4e, 0x7a, 0x13, 0x8d, 0x81, 0x74}}
|
||||
FOLDERID_RecordedTVLibrary = &KNOWNFOLDERID{0x1a6fdba2, 0xf42d, 0x4358, [8]byte{0xa7, 0x98, 0xb7, 0x4d, 0x74, 0x59, 0x26, 0xc5}}
|
||||
FOLDERID_HomeGroup = &KNOWNFOLDERID{0x52528a6b, 0xb9e3, 0x4add, [8]byte{0xb6, 0x0d, 0x58, 0x8c, 0x2d, 0xba, 0x84, 0x2d}}
|
||||
FOLDERID_HomeGroupCurrentUser = &KNOWNFOLDERID{0x9b74b6a3, 0x0dfd, 0x4f11, [8]byte{0x9e, 0x78, 0x5f, 0x78, 0x00, 0xf2, 0xe7, 0x72}}
|
||||
FOLDERID_DeviceMetadataStore = &KNOWNFOLDERID{0x5ce4a5e9, 0xe4eb, 0x479d, [8]byte{0xb8, 0x9f, 0x13, 0x0c, 0x02, 0x88, 0x61, 0x55}}
|
||||
FOLDERID_Libraries = &KNOWNFOLDERID{0x1b3ea5dc, 0xb587, 0x4786, [8]byte{0xb4, 0xef, 0xbd, 0x1d, 0xc3, 0x32, 0xae, 0xae}}
|
||||
FOLDERID_PublicLibraries = &KNOWNFOLDERID{0x48daf80b, 0xe6cf, 0x4f4e, [8]byte{0xb8, 0x00, 0x0e, 0x69, 0xd8, 0x4e, 0xe3, 0x84}}
|
||||
FOLDERID_UserPinned = &KNOWNFOLDERID{0x9e3995ab, 0x1f9c, 0x4f13, [8]byte{0xb8, 0x27, 0x48, 0xb2, 0x4b, 0x6c, 0x71, 0x74}}
|
||||
FOLDERID_ImplicitAppShortcuts = &KNOWNFOLDERID{0xbcb5256f, 0x79f6, 0x4cee, [8]byte{0xb7, 0x25, 0xdc, 0x34, 0xe4, 0x02, 0xfd, 0x46}}
|
||||
FOLDERID_AccountPictures = &KNOWNFOLDERID{0x008ca0b1, 0x55b4, 0x4c56, [8]byte{0xb8, 0xa8, 0x4d, 0xe4, 0xb2, 0x99, 0xd3, 0xbe}}
|
||||
FOLDERID_PublicUserTiles = &KNOWNFOLDERID{0x0482af6c, 0x08f1, 0x4c34, [8]byte{0x8c, 0x90, 0xe1, 0x7e, 0xc9, 0x8b, 0x1e, 0x17}}
|
||||
FOLDERID_AppsFolder = &KNOWNFOLDERID{0x1e87508d, 0x89c2, 0x42f0, [8]byte{0x8a, 0x7e, 0x64, 0x5a, 0x0f, 0x50, 0xca, 0x58}}
|
||||
FOLDERID_StartMenuAllPrograms = &KNOWNFOLDERID{0xf26305ef, 0x6948, 0x40b9, [8]byte{0xb2, 0x55, 0x81, 0x45, 0x3d, 0x09, 0xc7, 0x85}}
|
||||
FOLDERID_CommonStartMenuPlaces = &KNOWNFOLDERID{0xa440879f, 0x87a0, 0x4f7d, [8]byte{0xb7, 0x00, 0x02, 0x07, 0xb9, 0x66, 0x19, 0x4a}}
|
||||
FOLDERID_ApplicationShortcuts = &KNOWNFOLDERID{0xa3918781, 0xe5f2, 0x4890, [8]byte{0xb3, 0xd9, 0xa7, 0xe5, 0x43, 0x32, 0x32, 0x8c}}
|
||||
FOLDERID_RoamingTiles = &KNOWNFOLDERID{0x00bcfc5a, 0xed94, 0x4e48, [8]byte{0x96, 0xa1, 0x3f, 0x62, 0x17, 0xf2, 0x19, 0x90}}
|
||||
FOLDERID_RoamedTileImages = &KNOWNFOLDERID{0xaaa8d5a5, 0xf1d6, 0x4259, [8]byte{0xba, 0xa8, 0x78, 0xe7, 0xef, 0x60, 0x83, 0x5e}}
|
||||
FOLDERID_Screenshots = &KNOWNFOLDERID{0xb7bede81, 0xdf94, 0x4682, [8]byte{0xa7, 0xd8, 0x57, 0xa5, 0x26, 0x20, 0xb8, 0x6f}}
|
||||
FOLDERID_CameraRoll = &KNOWNFOLDERID{0xab5fb87b, 0x7ce2, 0x4f83, [8]byte{0x91, 0x5d, 0x55, 0x08, 0x46, 0xc9, 0x53, 0x7b}}
|
||||
FOLDERID_SkyDrive = &KNOWNFOLDERID{0xa52bba46, 0xe9e1, 0x435f, [8]byte{0xb3, 0xd9, 0x28, 0xda, 0xa6, 0x48, 0xc0, 0xf6}}
|
||||
FOLDERID_OneDrive = &KNOWNFOLDERID{0xa52bba46, 0xe9e1, 0x435f, [8]byte{0xb3, 0xd9, 0x28, 0xda, 0xa6, 0x48, 0xc0, 0xf6}}
|
||||
FOLDERID_SkyDriveDocuments = &KNOWNFOLDERID{0x24d89e24, 0x2f19, 0x4534, [8]byte{0x9d, 0xde, 0x6a, 0x66, 0x71, 0xfb, 0xb8, 0xfe}}
|
||||
FOLDERID_SkyDrivePictures = &KNOWNFOLDERID{0x339719b5, 0x8c47, 0x4894, [8]byte{0x94, 0xc2, 0xd8, 0xf7, 0x7a, 0xdd, 0x44, 0xa6}}
|
||||
FOLDERID_SkyDriveMusic = &KNOWNFOLDERID{0xc3f2459e, 0x80d6, 0x45dc, [8]byte{0xbf, 0xef, 0x1f, 0x76, 0x9f, 0x2b, 0xe7, 0x30}}
|
||||
FOLDERID_SkyDriveCameraRoll = &KNOWNFOLDERID{0x767e6811, 0x49cb, 0x4273, [8]byte{0x87, 0xc2, 0x20, 0xf3, 0x55, 0xe1, 0x08, 0x5b}}
|
||||
FOLDERID_SearchHistory = &KNOWNFOLDERID{0x0d4c3db6, 0x03a3, 0x462f, [8]byte{0xa0, 0xe6, 0x08, 0x92, 0x4c, 0x41, 0xb5, 0xd4}}
|
||||
FOLDERID_SearchTemplates = &KNOWNFOLDERID{0x7e636bfe, 0xdfa9, 0x4d5e, [8]byte{0xb4, 0x56, 0xd7, 0xb3, 0x98, 0x51, 0xd8, 0xa9}}
|
||||
FOLDERID_CameraRollLibrary = &KNOWNFOLDERID{0x2b20df75, 0x1eda, 0x4039, [8]byte{0x80, 0x97, 0x38, 0x79, 0x82, 0x27, 0xd5, 0xb7}}
|
||||
FOLDERID_SavedPictures = &KNOWNFOLDERID{0x3b193882, 0xd3ad, 0x4eab, [8]byte{0x96, 0x5a, 0x69, 0x82, 0x9d, 0x1f, 0xb5, 0x9f}}
|
||||
FOLDERID_SavedPicturesLibrary = &KNOWNFOLDERID{0xe25b5812, 0xbe88, 0x4bd9, [8]byte{0x94, 0xb0, 0x29, 0x23, 0x34, 0x77, 0xb6, 0xc3}}
|
||||
FOLDERID_RetailDemo = &KNOWNFOLDERID{0x12d4c69e, 0x24ad, 0x4923, [8]byte{0xbe, 0x19, 0x31, 0x32, 0x1c, 0x43, 0xa7, 0x67}}
|
||||
FOLDERID_Device = &KNOWNFOLDERID{0x1c2ac1dc, 0x4358, 0x4b6c, [8]byte{0x97, 0x33, 0xaf, 0x21, 0x15, 0x65, 0x76, 0xf0}}
|
||||
FOLDERID_DevelopmentFiles = &KNOWNFOLDERID{0xdbe8e08e, 0x3053, 0x4bbc, [8]byte{0xb1, 0x83, 0x2a, 0x7b, 0x2b, 0x19, 0x1e, 0x59}}
|
||||
FOLDERID_Objects3D = &KNOWNFOLDERID{0x31c0dd25, 0x9439, 0x4f12, [8]byte{0xbf, 0x41, 0x7f, 0xf4, 0xed, 0xa3, 0x87, 0x22}}
|
||||
FOLDERID_AppCaptures = &KNOWNFOLDERID{0xedc0fe71, 0x98d8, 0x4f4a, [8]byte{0xb9, 0x20, 0xc8, 0xdc, 0x13, 0x3c, 0xb1, 0x65}}
|
||||
FOLDERID_LocalDocuments = &KNOWNFOLDERID{0xf42ee2d3, 0x909f, 0x4907, [8]byte{0x88, 0x71, 0x4c, 0x22, 0xfc, 0x0b, 0xf7, 0x56}}
|
||||
FOLDERID_LocalPictures = &KNOWNFOLDERID{0x0ddd015d, 0xb06c, 0x45d5, [8]byte{0x8c, 0x4c, 0xf5, 0x97, 0x13, 0x85, 0x46, 0x39}}
|
||||
FOLDERID_LocalVideos = &KNOWNFOLDERID{0x35286a68, 0x3c57, 0x41a1, [8]byte{0xbb, 0xb1, 0x0e, 0xae, 0x73, 0xd7, 0x6c, 0x95}}
|
||||
FOLDERID_LocalMusic = &KNOWNFOLDERID{0xa0c69a99, 0x21c8, 0x4671, [8]byte{0x87, 0x03, 0x79, 0x34, 0x16, 0x2f, 0xcf, 0x1d}}
|
||||
FOLDERID_LocalDownloads = &KNOWNFOLDERID{0x7d83ee9b, 0x2244, 0x4e70, [8]byte{0xb1, 0xf5, 0x53, 0x93, 0x04, 0x2a, 0xf1, 0xe4}}
|
||||
FOLDERID_RecordedCalls = &KNOWNFOLDERID{0x2f8b40c2, 0x83ed, 0x48ee, [8]byte{0xb3, 0x83, 0xa1, 0xf1, 0x57, 0xec, 0x6f, 0x9a}}
|
||||
FOLDERID_AllAppMods = &KNOWNFOLDERID{0x7ad67899, 0x66af, 0x43ba, [8]byte{0x91, 0x56, 0x6a, 0xad, 0x42, 0xe6, 0xc5, 0x96}}
|
||||
FOLDERID_CurrentAppMods = &KNOWNFOLDERID{0x3db40b20, 0x2a30, 0x4dbe, [8]byte{0x91, 0x7e, 0x77, 0x1d, 0xd2, 0x1d, 0xd0, 0x99}}
|
||||
FOLDERID_AppDataDesktop = &KNOWNFOLDERID{0xb2c5e279, 0x7add, 0x439f, [8]byte{0xb2, 0x8c, 0xc4, 0x1f, 0xe1, 0xbb, 0xf6, 0x72}}
|
||||
FOLDERID_AppDataDocuments = &KNOWNFOLDERID{0x7be16610, 0x1f7f, 0x44ac, [8]byte{0xbf, 0xf0, 0x83, 0xe1, 0x5f, 0x2f, 0xfc, 0xa1}}
|
||||
FOLDERID_AppDataFavorites = &KNOWNFOLDERID{0x7cfbefbc, 0xde1f, 0x45aa, [8]byte{0xb8, 0x43, 0xa5, 0x42, 0xac, 0x53, 0x6c, 0xc9}}
|
||||
FOLDERID_AppDataProgramData = &KNOWNFOLDERID{0x559d40a3, 0xa036, 0x40fa, [8]byte{0xaf, 0x61, 0x84, 0xcb, 0x43, 0x0a, 0x4d, 0x34}}
|
||||
)
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,6 @@
|
|||
# git.rootprojects.org/root/go-gitver v1.1.3
|
||||
git.rootprojects.org/root/go-gitver
|
||||
git.rootprojects.org/root/go-gitver/gitver
|
||||
# golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7
|
||||
golang.org/x/sys/windows/registry
|
||||
golang.org/x/sys/windows
|
Loading…
Reference in New Issue