[mqtt] Implements mqtt publish tooling
This commit is contained in:
		
							
								
								
									
										284
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										284
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,284 @@ | |||||||
|  | # Created by .ignore support plugin (hsz.mobi) | ||||||
|  | ### Emacs template | ||||||
|  | # -*- mode: gitignore; -*- | ||||||
|  | *~ | ||||||
|  | \#*\# | ||||||
|  | /.emacs.desktop | ||||||
|  | /.emacs.desktop.lock | ||||||
|  | *.elc | ||||||
|  | auto-save-list | ||||||
|  | tramp | ||||||
|  | .\#* | ||||||
|  |  | ||||||
|  | # Org-mode | ||||||
|  | .org-id-locations | ||||||
|  | *_archive | ||||||
|  |  | ||||||
|  | # flymake-mode | ||||||
|  | *_flymake.* | ||||||
|  |  | ||||||
|  | # eshell files | ||||||
|  | /eshell/history | ||||||
|  | /eshell/lastdir | ||||||
|  |  | ||||||
|  | # elpa packages | ||||||
|  | /elpa/ | ||||||
|  |  | ||||||
|  | # reftex files | ||||||
|  | *.rel | ||||||
|  |  | ||||||
|  | # AUCTeX auto folder | ||||||
|  | /auto/ | ||||||
|  |  | ||||||
|  | # cask packages | ||||||
|  | .cask/ | ||||||
|  | dist/ | ||||||
|  |  | ||||||
|  | # Flycheck | ||||||
|  | flycheck_*.el | ||||||
|  |  | ||||||
|  | # server auth directory | ||||||
|  | /server/ | ||||||
|  |  | ||||||
|  | # projectiles files | ||||||
|  | .projectile | ||||||
|  |  | ||||||
|  | # directory configuration | ||||||
|  | .dir-locals.el | ||||||
|  |  | ||||||
|  | # network security | ||||||
|  | /network-security.data | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ### JetBrains template | ||||||
|  | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm | ||||||
|  | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 | ||||||
|  |  | ||||||
|  | # User-specific stuff | ||||||
|  | .idea/**/workspace.xml | ||||||
|  | .idea/**/tasks.xml | ||||||
|  | .idea/**/usage.statistics.xml | ||||||
|  | .idea/**/dictionaries | ||||||
|  | .idea/**/shelf | ||||||
|  |  | ||||||
|  | # Generated files | ||||||
|  | .idea/**/contentModel.xml | ||||||
|  |  | ||||||
|  | # Sensitive or high-churn files | ||||||
|  | .idea/**/dataSources/ | ||||||
|  | .idea/**/dataSources.ids | ||||||
|  | .idea/**/dataSources.local.xml | ||||||
|  | .idea/**/sqlDataSources.xml | ||||||
|  | .idea/**/dynamic.xml | ||||||
|  | .idea/**/uiDesigner.xml | ||||||
|  | .idea/**/dbnavigator.xml | ||||||
|  |  | ||||||
|  | # Gradle | ||||||
|  | .idea/**/gradle.xml | ||||||
|  | .idea/**/libraries | ||||||
|  |  | ||||||
|  | # Gradle and Maven with auto-import | ||||||
|  | # When using Gradle or Maven with auto-import, you should exclude module files, | ||||||
|  | # since they will be recreated, and may cause churn.  Uncomment if using | ||||||
|  | # auto-import. | ||||||
|  | # .idea/artifacts | ||||||
|  | # .idea/compiler.xml | ||||||
|  | # .idea/modules.xml | ||||||
|  | # .idea/*.iml | ||||||
|  | # .idea/modules | ||||||
|  | # *.iml | ||||||
|  | # *.ipr | ||||||
|  |  | ||||||
|  | # CMake | ||||||
|  | cmake-build-*/ | ||||||
|  |  | ||||||
|  | # Mongo Explorer plugin | ||||||
|  | .idea/**/mongoSettings.xml | ||||||
|  |  | ||||||
|  | # File-based project format | ||||||
|  | *.iws | ||||||
|  |  | ||||||
|  | # IntelliJ | ||||||
|  | out/ | ||||||
|  |  | ||||||
|  | # mpeltonen/sbt-idea plugin | ||||||
|  | .idea_modules/ | ||||||
|  |  | ||||||
|  | # JIRA plugin | ||||||
|  | atlassian-ide-plugin.xml | ||||||
|  |  | ||||||
|  | # Cursive Clojure plugin | ||||||
|  | .idea/replstate.xml | ||||||
|  |  | ||||||
|  | # Crashlytics plugin (for Android Studio and IntelliJ) | ||||||
|  | com_crashlytics_export_strings.xml | ||||||
|  | crashlytics.properties | ||||||
|  | crashlytics-build.properties | ||||||
|  | fabric.properties | ||||||
|  |  | ||||||
|  | # Editor-based Rest Client | ||||||
|  | .idea/httpRequests | ||||||
|  |  | ||||||
|  | # Android studio 3.1+ serialized cache file | ||||||
|  | .idea/caches/build_file_checksums.ser | ||||||
|  |  | ||||||
|  | ### Vim template | ||||||
|  | # Swap | ||||||
|  | [._]*.s[a-v][a-z] | ||||||
|  | !*.svg  # comment out if you don't need vector files | ||||||
|  | [._]*.sw[a-p] | ||||||
|  | [._]s[a-rt-v][a-z] | ||||||
|  | [._]ss[a-gi-z] | ||||||
|  | [._]sw[a-p] | ||||||
|  |  | ||||||
|  | # Session | ||||||
|  | Session.vim | ||||||
|  | Sessionx.vim | ||||||
|  |  | ||||||
|  | # Temporary | ||||||
|  | .netrwhist | ||||||
|  | *~ | ||||||
|  | # Auto-generated tag files | ||||||
|  | tags | ||||||
|  | # Persistent undo | ||||||
|  | [._]*.un~ | ||||||
|  |  | ||||||
|  | ### macOS template | ||||||
|  | # General | ||||||
|  | .DS_Store | ||||||
|  | .AppleDouble | ||||||
|  | .LSOverride | ||||||
|  |  | ||||||
|  | # Icon must end with two \r | ||||||
|  | Icon | ||||||
|  |  | ||||||
|  | # Thumbnails | ||||||
|  | ._* | ||||||
|  |  | ||||||
|  | # Files that might appear in the root of a volume | ||||||
|  | .DocumentRevisions-V100 | ||||||
|  | .fseventsd | ||||||
|  | .Spotlight-V100 | ||||||
|  | .TemporaryItems | ||||||
|  | .Trashes | ||||||
|  | .VolumeIcon.icns | ||||||
|  | .com.apple.timemachine.donotpresent | ||||||
|  |  | ||||||
|  | # Directories potentially created on remote AFP share | ||||||
|  | .AppleDB | ||||||
|  | .AppleDesktop | ||||||
|  | Network Trash Folder | ||||||
|  | Temporary Items | ||||||
|  | .apdisk | ||||||
|  |  | ||||||
|  | ### Xcode template | ||||||
|  | # Xcode | ||||||
|  | # | ||||||
|  | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore | ||||||
|  |  | ||||||
|  | ## User settings | ||||||
|  | xcuserdata/ | ||||||
|  |  | ||||||
|  | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) | ||||||
|  | *.xcscmblueprint | ||||||
|  | *.xccheckout | ||||||
|  |  | ||||||
|  | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) | ||||||
|  | build/ | ||||||
|  | DerivedData/ | ||||||
|  | *.moved-aside | ||||||
|  | *.pbxuser | ||||||
|  | !default.pbxuser | ||||||
|  | *.mode1v3 | ||||||
|  | !default.mode1v3 | ||||||
|  | *.mode2v3 | ||||||
|  | !default.mode2v3 | ||||||
|  | *.perspectivev3 | ||||||
|  | !default.perspectivev3 | ||||||
|  |  | ||||||
|  | ## Gcc Patch | ||||||
|  | /*.gcno | ||||||
|  |  | ||||||
|  | ### Go template | ||||||
|  | # Binaries for programs and plugins | ||||||
|  | *.exe | ||||||
|  | *.exe~ | ||||||
|  | *.dll | ||||||
|  | *.so | ||||||
|  | *.dylib | ||||||
|  |  | ||||||
|  | # Test binary, built with `go test -c` | ||||||
|  | *.test | ||||||
|  |  | ||||||
|  | # Output of the go coverage tool, specifically when used with LiteIDE | ||||||
|  | *.out | ||||||
|  |  | ||||||
|  | # Dependency directories (remove the comment below to include it) | ||||||
|  | # vendor/ | ||||||
|  |  | ||||||
|  | ### Eclipse template | ||||||
|  | .metadata | ||||||
|  | bin/ | ||||||
|  | tmp/ | ||||||
|  | *.tmp | ||||||
|  | *.bak | ||||||
|  | *.swp | ||||||
|  | *~.nib | ||||||
|  | local.properties | ||||||
|  | .settings/ | ||||||
|  | .loadpath | ||||||
|  | .recommenders | ||||||
|  |  | ||||||
|  | # External tool builders | ||||||
|  | .externalToolBuilders/ | ||||||
|  |  | ||||||
|  | # Locally stored "Eclipse launch configurations" | ||||||
|  | *.launch | ||||||
|  |  | ||||||
|  | # PyDev specific (Python IDE for Eclipse) | ||||||
|  | *.pydevproject | ||||||
|  |  | ||||||
|  | # CDT-specific (C/C++ Development Tooling) | ||||||
|  | .cproject | ||||||
|  |  | ||||||
|  | # CDT- autotools | ||||||
|  | .autotools | ||||||
|  |  | ||||||
|  | # Java annotation processor (APT) | ||||||
|  | .factorypath | ||||||
|  |  | ||||||
|  | # PDT-specific (PHP Development Tools) | ||||||
|  | .buildpath | ||||||
|  |  | ||||||
|  | # sbteclipse plugin | ||||||
|  | .target | ||||||
|  |  | ||||||
|  | # Tern plugin | ||||||
|  | .tern-project | ||||||
|  |  | ||||||
|  | # TeXlipse plugin | ||||||
|  | .texlipse | ||||||
|  |  | ||||||
|  | # STS (Spring Tool Suite) | ||||||
|  | .springBeans | ||||||
|  |  | ||||||
|  | # Code Recommenders | ||||||
|  | .recommenders/ | ||||||
|  |  | ||||||
|  | # Annotation Processing | ||||||
|  | .apt_generated/ | ||||||
|  | .apt_generated_test/ | ||||||
|  |  | ||||||
|  | # Scala IDE specific (Scala & Java development for Eclipse) | ||||||
|  | .cache-main | ||||||
|  | .scala_dependencies | ||||||
|  | .worksheet | ||||||
|  |  | ||||||
|  | ### VisualStudioCode template | ||||||
|  | .vscode/* | ||||||
|  | !.vscode/settings.json | ||||||
|  | !.vscode/tasks.json | ||||||
|  | !.vscode/launch.json | ||||||
|  | !.vscode/extensions.json | ||||||
|  | *.code-workspace | ||||||
|  |  | ||||||
							
								
								
									
										10
									
								
								go.mod
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								go.mod
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  | module github.com/cyrilix/robocar-base | ||||||
|  |  | ||||||
|  | go 1.13 | ||||||
|  |  | ||||||
|  | require ( | ||||||
|  | 	github.com/Microsoft/hcsshim v0.8.6 // indirect | ||||||
|  | 	github.com/eclipse/paho.mqtt.golang v1.2.0 | ||||||
|  | 	github.com/testcontainers/testcontainers-go v0.0.9 | ||||||
|  | 	golang.org/x/net v0.0.0-20191126235420-ef20fe5d7933 // indirect | ||||||
|  | ) | ||||||
							
								
								
									
										118
									
								
								go.sum
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								go.sum
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,118 @@ | |||||||
|  | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= | ||||||
|  | github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= | ||||||
|  | github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= | ||||||
|  | github.com/Microsoft/go-winio v0.4.11 h1:zoIOcVf0xPN1tnMVbTtEdI+P8OofVk3NObnwOQ6nK2Q= | ||||||
|  | github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= | ||||||
|  | github.com/Microsoft/hcsshim v0.8.6 h1:ZfF0+zZeYdzMIVMZHKtDKJvLHj76XCuVae/jNkjj0IA= | ||||||
|  | github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= | ||||||
|  | github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= | ||||||
|  | github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= | ||||||
|  | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= | ||||||
|  | github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc h1:TP+534wVlf61smEIq1nwLLAjQVEK2EADoW3CX9AuT+8= | ||||||
|  | github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= | ||||||
|  | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||||||
|  | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||||||
|  | github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible h1:dvc1KSkIYTVjZgHf/CTC2diTYC8PzhaA5sFISRfNVrE= | ||||||
|  | github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= | ||||||
|  | github.com/docker/docker v0.7.3-0.20190506211059-b20a14b54661 h1:ZuxGvIvF01nfc/G9RJ5Q7Va1zQE2WJyG18Zv3DqCEf4= | ||||||
|  | github.com/docker/docker v0.7.3-0.20190506211059-b20a14b54661/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= | ||||||
|  | github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= | ||||||
|  | github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= | ||||||
|  | github.com/docker/go-units v0.3.3 h1:Xk8S3Xj5sLGlG5g67hJmYMmUgXv5N4PhkjJHHqrwnTk= | ||||||
|  | github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= | ||||||
|  | github.com/eclipse/paho.mqtt.golang v1.2.0 h1:1F8mhG9+aO5/xpdtFkW4SxOJB67ukuDC3t2y2qayIX0= | ||||||
|  | github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts= | ||||||
|  | github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= | ||||||
|  | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= | ||||||
|  | github.com/go-redis/redis v6.15.6+incompatible h1:H9evprGPLI8+ci7fxQx6WNZHJSb7be8FqJQRhdQZ5Sg= | ||||||
|  | github.com/go-redis/redis v6.15.6+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= | ||||||
|  | github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= | ||||||
|  | github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= | ||||||
|  | github.com/gogo/protobuf v1.2.0 h1:xU6/SpYbvkNYiptHJYEDRseDLvYE7wSqhYYNy0QSUzI= | ||||||
|  | github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= | ||||||
|  | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= | ||||||
|  | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= | ||||||
|  | github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= | ||||||
|  | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= | ||||||
|  | github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ= | ||||||
|  | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= | ||||||
|  | github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8= | ||||||
|  | github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= | ||||||
|  | github.com/gorilla/mux v1.6.2 h1:Pgr17XVTNXAk3q/r4CpKzC5xBM/qW1uVLV+IhRZpIIk= | ||||||
|  | github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= | ||||||
|  | github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= | ||||||
|  | github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= | ||||||
|  | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= | ||||||
|  | github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= | ||||||
|  | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= | ||||||
|  | github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= | ||||||
|  | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= | ||||||
|  | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= | ||||||
|  | github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= | ||||||
|  | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= | ||||||
|  | github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c h1:nXxl5PrvVm2L/wCy8dQu6DMTwH4oIuGN8GJDAlqDdVE= | ||||||
|  | github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= | ||||||
|  | github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= | ||||||
|  | github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w= | ||||||
|  | github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= | ||||||
|  | github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo= | ||||||
|  | github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= | ||||||
|  | github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ= | ||||||
|  | github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= | ||||||
|  | github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= | ||||||
|  | github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= | ||||||
|  | github.com/opencontainers/runc v0.1.1 h1:GlxAyO6x8rfZYN9Tt0Kti5a/cP41iuiO2yYT0IJGY8Y= | ||||||
|  | github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= | ||||||
|  | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= | ||||||
|  | github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= | ||||||
|  | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= | ||||||
|  | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||||||
|  | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||||||
|  | github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= | ||||||
|  | github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo= | ||||||
|  | github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= | ||||||
|  | github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= | ||||||
|  | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||||||
|  | github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= | ||||||
|  | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= | ||||||
|  | github.com/testcontainers/testcontainers-go v0.0.9 h1:mwvFz+FkuQMqQ9oLkG4cVzPsZTRmrCo2NcaerJNaptA= | ||||||
|  | github.com/testcontainers/testcontainers-go v0.0.9/go.mod h1:0Qe9qqjNZgxHzzdHPWwmQ2D49FFO7920hLdJ4yUJXJI= | ||||||
|  | golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= | ||||||
|  | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= | ||||||
|  | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | ||||||
|  | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= | ||||||
|  | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | ||||||
|  | golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | ||||||
|  | golang.org/x/net v0.0.0-20191126235420-ef20fe5d7933 h1:e6HwijUxhDe+hPNjZQQn9bA5PW3vNmnN64U2ZW759Lk= | ||||||
|  | golang.org/x/net v0.0.0-20191126235420-ef20fe5d7933/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | ||||||
|  | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= | ||||||
|  | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA= | ||||||
|  | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||||
|  | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||||
|  | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||||
|  | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||||
|  | golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||||
|  | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= | ||||||
|  | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||||
|  | golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= | ||||||
|  | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | ||||||
|  | golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= | ||||||
|  | golang.org/x/tools v0.0.0-20180810170437-e96c4e24768d/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | ||||||
|  | golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | ||||||
|  | google.golang.org/appengine v1.1.0 h1:igQkv0AAhEIvTEpD5LIpAfav2eeVO9HBTjvKHVJPRSs= | ||||||
|  | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= | ||||||
|  | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc= | ||||||
|  | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= | ||||||
|  | google.golang.org/grpc v1.17.0 h1:TRJYBgMclJvGYn2rIMjj+h9KtMt5r1Ij7ODVRIZkwhk= | ||||||
|  | google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= | ||||||
|  | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||||||
|  | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||||||
|  | gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= | ||||||
|  | gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= | ||||||
|  | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= | ||||||
|  | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= | ||||||
|  | gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= | ||||||
|  | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | ||||||
|  | gotest.tools v0.0.0-20181223230014-1083505acf35 h1:zpdCK+REwbk+rqjJmHhiCN6iBIigrZ39glqSF0P3KF0= | ||||||
|  | gotest.tools v0.0.0-20181223230014-1083505acf35/go.mod h1:R//lfYlUuTOTfblYI3lGoAAAebUdzjvbmQsuB7Ykd90= | ||||||
|  | honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= | ||||||
							
								
								
									
										37
									
								
								mode/mode.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								mode/mode.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | |||||||
|  | package mode | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"log" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type DriveMode int | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	DriveModeInvalid = -1 | ||||||
|  | 	DriveModeUser    = iota | ||||||
|  | 	DriveModePilot | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func ToString(mode DriveMode) string { | ||||||
|  | 	switch mode { | ||||||
|  | 	case DriveModeUser: | ||||||
|  | 		return "user" | ||||||
|  | 	case DriveModePilot: | ||||||
|  | 		return "pilot" | ||||||
|  | 	default: | ||||||
|  | 		return "" | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func ParseString(val string) DriveMode { | ||||||
|  | 	switch val { | ||||||
|  | 	case "user": | ||||||
|  | 		return DriveModeUser | ||||||
|  | 	case "pilot": | ||||||
|  | 		return DriveModePilot | ||||||
|  | 	default: | ||||||
|  | 		log.Printf("invalid DriveMode: %v", val) | ||||||
|  | 		return DriveModeInvalid | ||||||
|  |  | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										40
									
								
								mode/mode_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								mode/mode_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | |||||||
|  | package mode | ||||||
|  |  | ||||||
|  | import "testing" | ||||||
|  |  | ||||||
|  | func TestToString(t *testing.T) { | ||||||
|  | 	cases := []struct{ | ||||||
|  | 		value DriveMode | ||||||
|  | 		expected string | ||||||
|  | 	}{ | ||||||
|  | 		{DriveModeUser, "user"}, | ||||||
|  | 		{DriveModePilot, "pilot"}, | ||||||
|  | 		{DriveModeInvalid, ""}, | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	for _, c := range cases{ | ||||||
|  | 		val := ToString(c.value) | ||||||
|  | 		if val != c.expected{ | ||||||
|  | 			t.Errorf("ToString(%v): %v, wants %v", c.value, val, c.expected) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestParseString(t *testing.T) { | ||||||
|  | 	cases := []struct{ | ||||||
|  | 		value string | ||||||
|  | 		expected DriveMode | ||||||
|  | 	}{ | ||||||
|  | 		{"user", DriveModeUser}, | ||||||
|  | 		{"pilot",DriveModePilot}, | ||||||
|  | 		{"", DriveModeInvalid}, | ||||||
|  | 		{"invalid", DriveModeInvalid}, | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	for _, c := range cases{ | ||||||
|  | 		val := ParseString(c.value) | ||||||
|  | 		if val != c.expected{ | ||||||
|  | 			t.Errorf("ParseString(%v): %v, wants %v", c.value, val, c.expected) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										146
									
								
								mqttdevice/mqttdevice.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								mqttdevice/mqttdevice.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,146 @@ | |||||||
|  | package mqttdevice | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"github.com/cyrilix/robocar-base/mode" | ||||||
|  | 	MQTT "github.com/eclipse/paho.mqtt.golang" | ||||||
|  | 	"io" | ||||||
|  | 	"log" | ||||||
|  | 	"strconv" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type Publisher interface { | ||||||
|  | 	Publish(topic string, payload MqttValue) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type Subscriber interface { | ||||||
|  | 	Subscribe(topic string, mh MQTT.MessageHandler) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type MQTTPubSub interface { | ||||||
|  | 	Publisher | ||||||
|  | 	Subscriber | ||||||
|  | 	io.Closer | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type pahoMqttPubSub struct { | ||||||
|  | 	Uri      string | ||||||
|  | 	Username string | ||||||
|  | 	Password string | ||||||
|  | 	ClientId string | ||||||
|  | 	Qos      int | ||||||
|  | 	Retain   bool | ||||||
|  | 	client   MQTT.Client | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func NewPahoMqttPubSub(uri string, username string, password string, clientId string, qos int, retain bool) MQTTPubSub { | ||||||
|  | 	p := pahoMqttPubSub{Uri: uri, Username: username, Password: password, ClientId: clientId, Qos: qos, Retain: retain} | ||||||
|  | 	p.Connect() | ||||||
|  | 	return &p | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Publish message to broker | ||||||
|  | func (p *pahoMqttPubSub) Publish(topic string, payload MqttValue) { | ||||||
|  | 	tokenResp := p.client.Publish(topic, byte(p.Qos), p.Retain, string(payload)) | ||||||
|  | 	if tokenResp.Error() != nil { | ||||||
|  | 		log.Fatalf("%+v\n", tokenResp.Error()) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Register func to execute on message | ||||||
|  | func (p *pahoMqttPubSub) Subscribe(topic string, callback MQTT.MessageHandler) { | ||||||
|  | 	tokenResp := p.client.Subscribe(topic, byte(p.Qos), callback) | ||||||
|  | 	if tokenResp.Error() != nil { | ||||||
|  | 		log.Fatalf("%+v\n", tokenResp.Error()) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Close connection to broker | ||||||
|  | func (p *pahoMqttPubSub) Close() error { | ||||||
|  | 	p.client.Disconnect(500) | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (p *pahoMqttPubSub) Connect() { | ||||||
|  | 	if p.client != nil && p.client.IsConnected() { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	//create a ClientOptions struct setting the broker address, clientid, turn | ||||||
|  | 	//off trace output and set the default message handler | ||||||
|  | 	opts := MQTT.NewClientOptions().AddBroker(p.Uri) | ||||||
|  | 	opts.SetUsername(p.Username) | ||||||
|  | 	opts.SetPassword(p.Password) | ||||||
|  | 	opts.SetClientID(p.ClientId) | ||||||
|  | 	opts.SetAutoReconnect(true) | ||||||
|  | 	opts.SetDefaultPublishHandler( | ||||||
|  | 		//define a function for the default message handler | ||||||
|  | 		func(client MQTT.Client, msg MQTT.Message) { | ||||||
|  | 			fmt.Printf("TOPIC: %s\n", msg.Topic()) | ||||||
|  | 			fmt.Printf("MSG: %s\n", msg.Payload()) | ||||||
|  | 		}) | ||||||
|  |  | ||||||
|  | 	//create and start a client using the above ClientOptions | ||||||
|  | 	p.client = MQTT.NewClient(opts) | ||||||
|  | 	if token := p.client.Connect(); token.Wait() && token.Error() != nil { | ||||||
|  | 		panic(token.Error()) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type MqttValue []byte | ||||||
|  |  | ||||||
|  | func NewMqttValue(v interface{}) MqttValue { | ||||||
|  | 	switch val := v.(type) { | ||||||
|  | 	case string: | ||||||
|  | 		return MqttValue(val) | ||||||
|  | 	case float32, float64: | ||||||
|  | 		return MqttValue(fmt.Sprintf("%0.2f", val)) | ||||||
|  | 	case int, int8, int16, int32, int64: | ||||||
|  | 		return MqttValue(fmt.Sprintf("%d", val)) | ||||||
|  | 	case mode.DriveMode: | ||||||
|  | 		return MqttValue(mode.ToString(val)) | ||||||
|  | 	case bool: | ||||||
|  | 		if val { | ||||||
|  | 			return []byte("ON") | ||||||
|  | 		} else { | ||||||
|  | 			return []byte("OFF") | ||||||
|  | 		} | ||||||
|  | 	case []byte: | ||||||
|  | 		return val | ||||||
|  | 	case MqttValue: | ||||||
|  | 		return val | ||||||
|  | 	default: | ||||||
|  | 		log.Printf("invalid mqtt value: %v", val) | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (m *MqttValue) IntValue() (int, error) { | ||||||
|  | 	return strconv.Atoi(string(*m)) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (m *MqttValue) Float32Value() (float32, error) { | ||||||
|  | 	val := string(*m) | ||||||
|  | 	r, err := strconv.ParseFloat(val, 32) | ||||||
|  | 	return float32(r), err | ||||||
|  | } | ||||||
|  | func (m *MqttValue) Float64Value() (float64, error) { | ||||||
|  | 	val := string(*m) | ||||||
|  | 	return strconv.ParseFloat(val, 64) | ||||||
|  | } | ||||||
|  | func (m *MqttValue) StringValue() (string, error) { | ||||||
|  | 	return string(*m), nil | ||||||
|  | } | ||||||
|  | func (m *MqttValue) ByteSliceValue() ([]byte, error) { | ||||||
|  | 	return *m, nil | ||||||
|  | } | ||||||
|  | func (m *MqttValue) BoolValue() (bool, error) { | ||||||
|  | 	val := string(*m) | ||||||
|  | 	switch val { | ||||||
|  | 	case "ON": | ||||||
|  | 		return true, nil | ||||||
|  | 	case "OFF": | ||||||
|  | 		return false, nil | ||||||
|  | 	default: | ||||||
|  | 		return false, fmt.Errorf("value %v can't be converted to bool", val) | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										189
									
								
								mqttdevice/mqttdevice_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										189
									
								
								mqttdevice/mqttdevice_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,189 @@ | |||||||
|  | package mqttdevice | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"github.com/cyrilix/robocar-base/testtools" | ||||||
|  | 	mqtt "github.com/eclipse/paho.mqtt.golang" | ||||||
|  | 	"testing" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func TestIntegration(t *testing.T) { | ||||||
|  |  | ||||||
|  | 	ctx, mqttC, mqttUri := testtools.MqttContainer(t) | ||||||
|  | 	defer mqttC.Terminate(ctx) | ||||||
|  |  | ||||||
|  | 	t.Run("ConnectAndClose", func(t *testing.T) { | ||||||
|  | 		t.Logf("Mqtt connection %s ready", mqttUri) | ||||||
|  |  | ||||||
|  | 		p := pahoMqttPubSub{Uri: mqttUri, ClientId: "TestMqtt", Username: "guest", Password: "guest"} | ||||||
|  | 		p.Connect() | ||||||
|  | 		p.Close() | ||||||
|  | 	}) | ||||||
|  | 	t.Run("Publish", func(t *testing.T) { | ||||||
|  | 		options := mqtt.NewClientOptions().AddBroker(mqttUri) | ||||||
|  | 		options.SetUsername("guest") | ||||||
|  | 		options.SetPassword("guest") | ||||||
|  |  | ||||||
|  | 		client := mqtt.NewClient(options) | ||||||
|  | 		token := client.Connect() | ||||||
|  | 		defer client.Disconnect(100) | ||||||
|  | 		token.Wait() | ||||||
|  | 		if token.Error() != nil { | ||||||
|  | 			t.Fatalf("unable to connect to mqtt broker: %v\n", token.Error()) | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		c := make(chan string) | ||||||
|  | 		defer close(c) | ||||||
|  | 		client.Subscribe("test/publish", 0, func(client mqtt.Client, message mqtt.Message) { | ||||||
|  | 			c <- string(message.Payload()) | ||||||
|  | 		}).Wait() | ||||||
|  |  | ||||||
|  | 		p := pahoMqttPubSub{Uri: mqttUri, ClientId: "TestMqtt", Username: "guest", Password: "guest"} | ||||||
|  | 		p.Connect() | ||||||
|  | 		defer p.Close() | ||||||
|  |  | ||||||
|  | 		p.Publish("test/publish", []byte("Test1234")) | ||||||
|  | 		result := <-c | ||||||
|  | 		if result != "Test1234" { | ||||||
|  | 			t.Fatalf("bad message: %v\n", result) | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestNewMqttValue(t *testing.T) { | ||||||
|  | 	cases := []struct { | ||||||
|  | 		value    interface{} | ||||||
|  | 		expected MqttValue | ||||||
|  | 	}{ | ||||||
|  | 		{"text", []byte("text")}, | ||||||
|  | 		{float32(2.0123), []byte("2.01")}, | ||||||
|  | 		{3.12345, []byte("3.12")}, | ||||||
|  | 		{12, []byte("12")}, | ||||||
|  | 		{true, []byte("ON")}, | ||||||
|  | 		{false, []byte("OFF")}, | ||||||
|  | 		{MqttValue("13"), []byte("13")}, | ||||||
|  | 		{[]byte("test bytes"), []byte("test bytes")}, | ||||||
|  |  | ||||||
|  | 		{struct { | ||||||
|  | 			content string | ||||||
|  | 		}{"invalid"}, nil}, | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	for _, c := range cases { | ||||||
|  | 		val := NewMqttValue(c.value) | ||||||
|  | 		if string(val) != string(c.expected) { | ||||||
|  | 			t.Errorf("NewMqttValue(%v): %v, wants %v", c.value, val, c.expected) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestMqttValue_BoolValue(t *testing.T) { | ||||||
|  | 	cases := []struct { | ||||||
|  | 		value    MqttValue | ||||||
|  | 		expected bool | ||||||
|  | 	}{ | ||||||
|  | 		{NewMqttValue("ON"), true}, | ||||||
|  | 		{NewMqttValue("OFF"), false}, | ||||||
|  | 	} | ||||||
|  | 	for _, c := range cases { | ||||||
|  | 		val, err := c.value.BoolValue() | ||||||
|  | 		if err != nil { | ||||||
|  | 			t.Errorf("unexpected conversion error: %v", err) | ||||||
|  | 		} | ||||||
|  | 		if c.expected != val { | ||||||
|  | 			t.Errorf("MqttValue.BoolValue(): %v, wants %v", val, c.expected) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestMqttValue_ByteSliceValue(t *testing.T) { | ||||||
|  | 	cases := []struct { | ||||||
|  | 		value    MqttValue | ||||||
|  | 		expected []byte | ||||||
|  | 	}{ | ||||||
|  | 		{NewMqttValue([]byte("content")), []byte("content")}, | ||||||
|  | 	} | ||||||
|  | 	for _, c := range cases{ | ||||||
|  | 		val, err := c.value.ByteSliceValue() | ||||||
|  | 		if err != nil { | ||||||
|  | 			t.Errorf("unexpected conversion error: %v", err) | ||||||
|  | 		} | ||||||
|  | 		if string(c.expected) != string(val){ | ||||||
|  | 			t.Errorf("MqttValue.BoolValue(): %v, wants %v", val, c.expected) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestMqttValue_Float32Value(t *testing.T) { | ||||||
|  | 	cases := []struct { | ||||||
|  | 		value    MqttValue | ||||||
|  | 		expected float32 | ||||||
|  | 	}{ | ||||||
|  | 		{NewMqttValue("32.0123"), float32(32.0123)}, | ||||||
|  | 		{NewMqttValue("33"), float32(33.)}, | ||||||
|  | 	} | ||||||
|  | 	for _, c := range cases{ | ||||||
|  | 		val, err := c.value.Float32Value() | ||||||
|  | 		if err != nil { | ||||||
|  | 			t.Errorf("unexpected conversion error: %v", err) | ||||||
|  | 		} | ||||||
|  | 		if c.expected != val{ | ||||||
|  | 			t.Errorf("MqttValue.BoolValue(): %v, wants %v", val, c.expected) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestMqttValue_Float64Value(t *testing.T) { | ||||||
|  | 	cases := []struct { | ||||||
|  | 		value    MqttValue | ||||||
|  | 		expected float64 | ||||||
|  | 	}{ | ||||||
|  | 		{NewMqttValue("32.0123"), 32.0123}, | ||||||
|  | 		{NewMqttValue("33"), 33.}, | ||||||
|  | 	} | ||||||
|  | 	for _, c := range cases{ | ||||||
|  | 		val, err := c.value.Float64Value() | ||||||
|  | 		if err != nil { | ||||||
|  | 			t.Errorf("unexpected conversion error: %v", err) | ||||||
|  | 		} | ||||||
|  | 		if c.expected != val{ | ||||||
|  | 			t.Errorf("MqttValue.BoolValue(): %v, wants %v", val, c.expected) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | func TestMqttValue_IntValue(t *testing.T) { | ||||||
|  | 	cases := []struct { | ||||||
|  | 		value    MqttValue | ||||||
|  | 		expected int | ||||||
|  | 	}{ | ||||||
|  | 		{NewMqttValue("1"), 1}, | ||||||
|  | 		{NewMqttValue("-10"), -10}, | ||||||
|  | 	} | ||||||
|  | 	for _, c := range cases{ | ||||||
|  | 		val, err := c.value.IntValue() | ||||||
|  | 		if err != nil { | ||||||
|  | 			t.Errorf("unexpected conversion error: %v", err) | ||||||
|  | 		} | ||||||
|  | 		if c.expected != val{ | ||||||
|  | 			t.Errorf("MqttValue.BoolValue(): %v, wants %v", val, c.expected) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | func TestMqttValue_StringValue(t *testing.T) { | ||||||
|  | 	cases := []struct { | ||||||
|  | 		value    MqttValue | ||||||
|  | 		expected string | ||||||
|  | 	}{ | ||||||
|  | 		{NewMqttValue("ON"), "ON"}, | ||||||
|  | 		{NewMqttValue("OFF"), "OFF"}, | ||||||
|  | 	} | ||||||
|  | 	for _, c := range cases{ | ||||||
|  | 		val, err := c.value.StringValue() | ||||||
|  | 		if err != nil { | ||||||
|  | 			t.Errorf("unexpected conversion error: %v", err) | ||||||
|  | 		} | ||||||
|  | 		if c.expected != val{ | ||||||
|  | 			t.Errorf("MqttValue.BoolValue(): %v, wants %v", val, c.expected) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										37
									
								
								testtools/testtools.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								testtools/testtools.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | |||||||
|  | package testtools | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"context" | ||||||
|  | 	"fmt" | ||||||
|  | 	"github.com/testcontainers/testcontainers-go" | ||||||
|  | 	"github.com/testcontainers/testcontainers-go/wait" | ||||||
|  | 	"testing" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func MqttContainer(t *testing.T) (context.Context, testcontainers.Container, string) { | ||||||
|  | 	ctx := context.Background() | ||||||
|  | 	req := testcontainers.ContainerRequest{ | ||||||
|  | 		Image:        "eclipse-mosquitto", | ||||||
|  | 		ExposedPorts: []string{"1883/tcp"}, | ||||||
|  | 		WaitingFor:   wait.ForLog("listen socket on port 1883."), | ||||||
|  | 	} | ||||||
|  | 	mqttC, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ | ||||||
|  | 		ContainerRequest: req, | ||||||
|  | 		Started:          true, | ||||||
|  | 	}) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Error(err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	ip, err := mqttC.Host(ctx) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Error(err) | ||||||
|  | 	} | ||||||
|  | 	port, err := mqttC.MappedPort(ctx, "1883/tcp") | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Error(err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	mqttUri := fmt.Sprintf("tcp://%s:%d", ip, port.Int()) | ||||||
|  | 	return ctx, mqttC, mqttUri | ||||||
|  | } | ||||||
							
								
								
									
										1
									
								
								vendor/github.com/Microsoft/go-winio/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/Microsoft/go-winio/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | *.exe | ||||||
							
								
								
									
										22
									
								
								vendor/github.com/Microsoft/go-winio/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								vendor/github.com/Microsoft/go-winio/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | |||||||
|  | The MIT License (MIT) | ||||||
|  |  | ||||||
|  | Copyright (c) 2015 Microsoft | ||||||
|  |  | ||||||
|  | Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  | of this software and associated documentation files (the "Software"), to deal | ||||||
|  | in the Software without restriction, including without limitation the rights | ||||||
|  | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  | copies of the Software, and to permit persons to whom the Software is | ||||||
|  | furnished to do so, subject to the following conditions: | ||||||
|  |  | ||||||
|  | The above copyright notice and this permission notice shall be included in all | ||||||
|  | copies or substantial portions of the Software. | ||||||
|  |  | ||||||
|  | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||||
|  | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||||
|  | SOFTWARE. | ||||||
|  |  | ||||||
							
								
								
									
										22
									
								
								vendor/github.com/Microsoft/go-winio/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								vendor/github.com/Microsoft/go-winio/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | |||||||
|  | # go-winio | ||||||
|  |  | ||||||
|  | This repository contains utilities for efficiently performing Win32 IO operations in | ||||||
|  | Go. Currently, this is focused on accessing named pipes and other file handles, and | ||||||
|  | for using named pipes as a net transport. | ||||||
|  |  | ||||||
|  | This code relies on IO completion ports to avoid blocking IO on system threads, allowing Go | ||||||
|  | to reuse the thread to schedule another goroutine. This limits support to Windows Vista and | ||||||
|  | newer operating systems. This is similar to the implementation of network sockets in Go's net | ||||||
|  | package. | ||||||
|  |  | ||||||
|  | Please see the LICENSE file for licensing information. | ||||||
|  |  | ||||||
|  | This project has adopted the [Microsoft Open Source Code of | ||||||
|  | Conduct](https://opensource.microsoft.com/codeofconduct/). For more information | ||||||
|  | see the [Code of Conduct | ||||||
|  | FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact | ||||||
|  | [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional | ||||||
|  | questions or comments. | ||||||
|  |  | ||||||
|  | Thanks to natefinch for the inspiration for this library. See https://github.com/natefinch/npipe | ||||||
|  | for another named pipe implementation. | ||||||
							
								
								
									
										280
									
								
								vendor/github.com/Microsoft/go-winio/backup.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										280
									
								
								vendor/github.com/Microsoft/go-winio/backup.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,280 @@ | |||||||
|  | // +build windows | ||||||
|  |  | ||||||
|  | package winio | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"encoding/binary" | ||||||
|  | 	"errors" | ||||||
|  | 	"fmt" | ||||||
|  | 	"io" | ||||||
|  | 	"io/ioutil" | ||||||
|  | 	"os" | ||||||
|  | 	"runtime" | ||||||
|  | 	"syscall" | ||||||
|  | 	"unicode/utf16" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | //sys backupRead(h syscall.Handle, b []byte, bytesRead *uint32, abort bool, processSecurity bool, context *uintptr) (err error) = BackupRead | ||||||
|  | //sys backupWrite(h syscall.Handle, b []byte, bytesWritten *uint32, abort bool, processSecurity bool, context *uintptr) (err error) = BackupWrite | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	BackupData = uint32(iota + 1) | ||||||
|  | 	BackupEaData | ||||||
|  | 	BackupSecurity | ||||||
|  | 	BackupAlternateData | ||||||
|  | 	BackupLink | ||||||
|  | 	BackupPropertyData | ||||||
|  | 	BackupObjectId | ||||||
|  | 	BackupReparseData | ||||||
|  | 	BackupSparseBlock | ||||||
|  | 	BackupTxfsData | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	StreamSparseAttributes = uint32(8) | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	WRITE_DAC              = 0x40000 | ||||||
|  | 	WRITE_OWNER            = 0x80000 | ||||||
|  | 	ACCESS_SYSTEM_SECURITY = 0x1000000 | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // BackupHeader represents a backup stream of a file. | ||||||
|  | type BackupHeader struct { | ||||||
|  | 	Id         uint32 // The backup stream ID | ||||||
|  | 	Attributes uint32 // Stream attributes | ||||||
|  | 	Size       int64  // The size of the stream in bytes | ||||||
|  | 	Name       string // The name of the stream (for BackupAlternateData only). | ||||||
|  | 	Offset     int64  // The offset of the stream in the file (for BackupSparseBlock only). | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type win32StreamId struct { | ||||||
|  | 	StreamId   uint32 | ||||||
|  | 	Attributes uint32 | ||||||
|  | 	Size       uint64 | ||||||
|  | 	NameSize   uint32 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // BackupStreamReader reads from a stream produced by the BackupRead Win32 API and produces a series | ||||||
|  | // of BackupHeader values. | ||||||
|  | type BackupStreamReader struct { | ||||||
|  | 	r         io.Reader | ||||||
|  | 	bytesLeft int64 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // NewBackupStreamReader produces a BackupStreamReader from any io.Reader. | ||||||
|  | func NewBackupStreamReader(r io.Reader) *BackupStreamReader { | ||||||
|  | 	return &BackupStreamReader{r, 0} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Next returns the next backup stream and prepares for calls to Read(). It skips the remainder of the current stream if | ||||||
|  | // it was not completely read. | ||||||
|  | func (r *BackupStreamReader) Next() (*BackupHeader, error) { | ||||||
|  | 	if r.bytesLeft > 0 { | ||||||
|  | 		if s, ok := r.r.(io.Seeker); ok { | ||||||
|  | 			// Make sure Seek on io.SeekCurrent sometimes succeeds | ||||||
|  | 			// before trying the actual seek. | ||||||
|  | 			if _, err := s.Seek(0, io.SeekCurrent); err == nil { | ||||||
|  | 				if _, err = s.Seek(r.bytesLeft, io.SeekCurrent); err != nil { | ||||||
|  | 					return nil, err | ||||||
|  | 				} | ||||||
|  | 				r.bytesLeft = 0 | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		if _, err := io.Copy(ioutil.Discard, r); err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	var wsi win32StreamId | ||||||
|  | 	if err := binary.Read(r.r, binary.LittleEndian, &wsi); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	hdr := &BackupHeader{ | ||||||
|  | 		Id:         wsi.StreamId, | ||||||
|  | 		Attributes: wsi.Attributes, | ||||||
|  | 		Size:       int64(wsi.Size), | ||||||
|  | 	} | ||||||
|  | 	if wsi.NameSize != 0 { | ||||||
|  | 		name := make([]uint16, int(wsi.NameSize/2)) | ||||||
|  | 		if err := binary.Read(r.r, binary.LittleEndian, name); err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 		hdr.Name = syscall.UTF16ToString(name) | ||||||
|  | 	} | ||||||
|  | 	if wsi.StreamId == BackupSparseBlock { | ||||||
|  | 		if err := binary.Read(r.r, binary.LittleEndian, &hdr.Offset); err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 		hdr.Size -= 8 | ||||||
|  | 	} | ||||||
|  | 	r.bytesLeft = hdr.Size | ||||||
|  | 	return hdr, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Read reads from the current backup stream. | ||||||
|  | func (r *BackupStreamReader) Read(b []byte) (int, error) { | ||||||
|  | 	if r.bytesLeft == 0 { | ||||||
|  | 		return 0, io.EOF | ||||||
|  | 	} | ||||||
|  | 	if int64(len(b)) > r.bytesLeft { | ||||||
|  | 		b = b[:r.bytesLeft] | ||||||
|  | 	} | ||||||
|  | 	n, err := r.r.Read(b) | ||||||
|  | 	r.bytesLeft -= int64(n) | ||||||
|  | 	if err == io.EOF { | ||||||
|  | 		err = io.ErrUnexpectedEOF | ||||||
|  | 	} else if r.bytesLeft == 0 && err == nil { | ||||||
|  | 		err = io.EOF | ||||||
|  | 	} | ||||||
|  | 	return n, err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // BackupStreamWriter writes a stream compatible with the BackupWrite Win32 API. | ||||||
|  | type BackupStreamWriter struct { | ||||||
|  | 	w         io.Writer | ||||||
|  | 	bytesLeft int64 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // NewBackupStreamWriter produces a BackupStreamWriter on top of an io.Writer. | ||||||
|  | func NewBackupStreamWriter(w io.Writer) *BackupStreamWriter { | ||||||
|  | 	return &BackupStreamWriter{w, 0} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // WriteHeader writes the next backup stream header and prepares for calls to Write(). | ||||||
|  | func (w *BackupStreamWriter) WriteHeader(hdr *BackupHeader) error { | ||||||
|  | 	if w.bytesLeft != 0 { | ||||||
|  | 		return fmt.Errorf("missing %d bytes", w.bytesLeft) | ||||||
|  | 	} | ||||||
|  | 	name := utf16.Encode([]rune(hdr.Name)) | ||||||
|  | 	wsi := win32StreamId{ | ||||||
|  | 		StreamId:   hdr.Id, | ||||||
|  | 		Attributes: hdr.Attributes, | ||||||
|  | 		Size:       uint64(hdr.Size), | ||||||
|  | 		NameSize:   uint32(len(name) * 2), | ||||||
|  | 	} | ||||||
|  | 	if hdr.Id == BackupSparseBlock { | ||||||
|  | 		// Include space for the int64 block offset | ||||||
|  | 		wsi.Size += 8 | ||||||
|  | 	} | ||||||
|  | 	if err := binary.Write(w.w, binary.LittleEndian, &wsi); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	if len(name) != 0 { | ||||||
|  | 		if err := binary.Write(w.w, binary.LittleEndian, name); err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if hdr.Id == BackupSparseBlock { | ||||||
|  | 		if err := binary.Write(w.w, binary.LittleEndian, hdr.Offset); err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	w.bytesLeft = hdr.Size | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Write writes to the current backup stream. | ||||||
|  | func (w *BackupStreamWriter) Write(b []byte) (int, error) { | ||||||
|  | 	if w.bytesLeft < int64(len(b)) { | ||||||
|  | 		return 0, fmt.Errorf("too many bytes by %d", int64(len(b))-w.bytesLeft) | ||||||
|  | 	} | ||||||
|  | 	n, err := w.w.Write(b) | ||||||
|  | 	w.bytesLeft -= int64(n) | ||||||
|  | 	return n, err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // BackupFileReader provides an io.ReadCloser interface on top of the BackupRead Win32 API. | ||||||
|  | type BackupFileReader struct { | ||||||
|  | 	f               *os.File | ||||||
|  | 	includeSecurity bool | ||||||
|  | 	ctx             uintptr | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // NewBackupFileReader returns a new BackupFileReader from a file handle. If includeSecurity is true, | ||||||
|  | // Read will attempt to read the security descriptor of the file. | ||||||
|  | func NewBackupFileReader(f *os.File, includeSecurity bool) *BackupFileReader { | ||||||
|  | 	r := &BackupFileReader{f, includeSecurity, 0} | ||||||
|  | 	return r | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Read reads a backup stream from the file by calling the Win32 API BackupRead(). | ||||||
|  | func (r *BackupFileReader) Read(b []byte) (int, error) { | ||||||
|  | 	var bytesRead uint32 | ||||||
|  | 	err := backupRead(syscall.Handle(r.f.Fd()), b, &bytesRead, false, r.includeSecurity, &r.ctx) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return 0, &os.PathError{"BackupRead", r.f.Name(), err} | ||||||
|  | 	} | ||||||
|  | 	runtime.KeepAlive(r.f) | ||||||
|  | 	if bytesRead == 0 { | ||||||
|  | 		return 0, io.EOF | ||||||
|  | 	} | ||||||
|  | 	return int(bytesRead), nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Close frees Win32 resources associated with the BackupFileReader. It does not close | ||||||
|  | // the underlying file. | ||||||
|  | func (r *BackupFileReader) Close() error { | ||||||
|  | 	if r.ctx != 0 { | ||||||
|  | 		backupRead(syscall.Handle(r.f.Fd()), nil, nil, true, false, &r.ctx) | ||||||
|  | 		runtime.KeepAlive(r.f) | ||||||
|  | 		r.ctx = 0 | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // BackupFileWriter provides an io.WriteCloser interface on top of the BackupWrite Win32 API. | ||||||
|  | type BackupFileWriter struct { | ||||||
|  | 	f               *os.File | ||||||
|  | 	includeSecurity bool | ||||||
|  | 	ctx             uintptr | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // NewBackupFileWriter returns a new BackupFileWriter from a file handle. If includeSecurity is true, | ||||||
|  | // Write() will attempt to restore the security descriptor from the stream. | ||||||
|  | func NewBackupFileWriter(f *os.File, includeSecurity bool) *BackupFileWriter { | ||||||
|  | 	w := &BackupFileWriter{f, includeSecurity, 0} | ||||||
|  | 	return w | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Write restores a portion of the file using the provided backup stream. | ||||||
|  | func (w *BackupFileWriter) Write(b []byte) (int, error) { | ||||||
|  | 	var bytesWritten uint32 | ||||||
|  | 	err := backupWrite(syscall.Handle(w.f.Fd()), b, &bytesWritten, false, w.includeSecurity, &w.ctx) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return 0, &os.PathError{"BackupWrite", w.f.Name(), err} | ||||||
|  | 	} | ||||||
|  | 	runtime.KeepAlive(w.f) | ||||||
|  | 	if int(bytesWritten) != len(b) { | ||||||
|  | 		return int(bytesWritten), errors.New("not all bytes could be written") | ||||||
|  | 	} | ||||||
|  | 	return len(b), nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Close frees Win32 resources associated with the BackupFileWriter. It does not | ||||||
|  | // close the underlying file. | ||||||
|  | func (w *BackupFileWriter) Close() error { | ||||||
|  | 	if w.ctx != 0 { | ||||||
|  | 		backupWrite(syscall.Handle(w.f.Fd()), nil, nil, true, false, &w.ctx) | ||||||
|  | 		runtime.KeepAlive(w.f) | ||||||
|  | 		w.ctx = 0 | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // OpenForBackup opens a file or directory, potentially skipping access checks if the backup | ||||||
|  | // or restore privileges have been acquired. | ||||||
|  | // | ||||||
|  | // If the file opened was a directory, it cannot be used with Readdir(). | ||||||
|  | func OpenForBackup(path string, access uint32, share uint32, createmode uint32) (*os.File, error) { | ||||||
|  | 	winPath, err := syscall.UTF16FromString(path) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	h, err := syscall.CreateFile(&winPath[0], access, share, nil, createmode, syscall.FILE_FLAG_BACKUP_SEMANTICS|syscall.FILE_FLAG_OPEN_REPARSE_POINT, 0) | ||||||
|  | 	if err != nil { | ||||||
|  | 		err = &os.PathError{Op: "open", Path: path, Err: err} | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return os.NewFile(uintptr(h), path), nil | ||||||
|  | } | ||||||
							
								
								
									
										137
									
								
								vendor/github.com/Microsoft/go-winio/ea.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										137
									
								
								vendor/github.com/Microsoft/go-winio/ea.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,137 @@ | |||||||
|  | package winio | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"bytes" | ||||||
|  | 	"encoding/binary" | ||||||
|  | 	"errors" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type fileFullEaInformation struct { | ||||||
|  | 	NextEntryOffset uint32 | ||||||
|  | 	Flags           uint8 | ||||||
|  | 	NameLength      uint8 | ||||||
|  | 	ValueLength     uint16 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | var ( | ||||||
|  | 	fileFullEaInformationSize = binary.Size(&fileFullEaInformation{}) | ||||||
|  |  | ||||||
|  | 	errInvalidEaBuffer = errors.New("invalid extended attribute buffer") | ||||||
|  | 	errEaNameTooLarge  = errors.New("extended attribute name too large") | ||||||
|  | 	errEaValueTooLarge = errors.New("extended attribute value too large") | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // ExtendedAttribute represents a single Windows EA. | ||||||
|  | type ExtendedAttribute struct { | ||||||
|  | 	Name  string | ||||||
|  | 	Value []byte | ||||||
|  | 	Flags uint8 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func parseEa(b []byte) (ea ExtendedAttribute, nb []byte, err error) { | ||||||
|  | 	var info fileFullEaInformation | ||||||
|  | 	err = binary.Read(bytes.NewReader(b), binary.LittleEndian, &info) | ||||||
|  | 	if err != nil { | ||||||
|  | 		err = errInvalidEaBuffer | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	nameOffset := fileFullEaInformationSize | ||||||
|  | 	nameLen := int(info.NameLength) | ||||||
|  | 	valueOffset := nameOffset + int(info.NameLength) + 1 | ||||||
|  | 	valueLen := int(info.ValueLength) | ||||||
|  | 	nextOffset := int(info.NextEntryOffset) | ||||||
|  | 	if valueLen+valueOffset > len(b) || nextOffset < 0 || nextOffset > len(b) { | ||||||
|  | 		err = errInvalidEaBuffer | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	ea.Name = string(b[nameOffset : nameOffset+nameLen]) | ||||||
|  | 	ea.Value = b[valueOffset : valueOffset+valueLen] | ||||||
|  | 	ea.Flags = info.Flags | ||||||
|  | 	if info.NextEntryOffset != 0 { | ||||||
|  | 		nb = b[info.NextEntryOffset:] | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // DecodeExtendedAttributes decodes a list of EAs from a FILE_FULL_EA_INFORMATION | ||||||
|  | // buffer retrieved from BackupRead, ZwQueryEaFile, etc. | ||||||
|  | func DecodeExtendedAttributes(b []byte) (eas []ExtendedAttribute, err error) { | ||||||
|  | 	for len(b) != 0 { | ||||||
|  | 		ea, nb, err := parseEa(b) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		eas = append(eas, ea) | ||||||
|  | 		b = nb | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func writeEa(buf *bytes.Buffer, ea *ExtendedAttribute, last bool) error { | ||||||
|  | 	if int(uint8(len(ea.Name))) != len(ea.Name) { | ||||||
|  | 		return errEaNameTooLarge | ||||||
|  | 	} | ||||||
|  | 	if int(uint16(len(ea.Value))) != len(ea.Value) { | ||||||
|  | 		return errEaValueTooLarge | ||||||
|  | 	} | ||||||
|  | 	entrySize := uint32(fileFullEaInformationSize + len(ea.Name) + 1 + len(ea.Value)) | ||||||
|  | 	withPadding := (entrySize + 3) &^ 3 | ||||||
|  | 	nextOffset := uint32(0) | ||||||
|  | 	if !last { | ||||||
|  | 		nextOffset = withPadding | ||||||
|  | 	} | ||||||
|  | 	info := fileFullEaInformation{ | ||||||
|  | 		NextEntryOffset: nextOffset, | ||||||
|  | 		Flags:           ea.Flags, | ||||||
|  | 		NameLength:      uint8(len(ea.Name)), | ||||||
|  | 		ValueLength:     uint16(len(ea.Value)), | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	err := binary.Write(buf, binary.LittleEndian, &info) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	_, err = buf.Write([]byte(ea.Name)) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	err = buf.WriteByte(0) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	_, err = buf.Write(ea.Value) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	_, err = buf.Write([]byte{0, 0, 0}[0 : withPadding-entrySize]) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // EncodeExtendedAttributes encodes a list of EAs into a FILE_FULL_EA_INFORMATION | ||||||
|  | // buffer for use with BackupWrite, ZwSetEaFile, etc. | ||||||
|  | func EncodeExtendedAttributes(eas []ExtendedAttribute) ([]byte, error) { | ||||||
|  | 	var buf bytes.Buffer | ||||||
|  | 	for i := range eas { | ||||||
|  | 		last := false | ||||||
|  | 		if i == len(eas)-1 { | ||||||
|  | 			last = true | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		err := writeEa(&buf, &eas[i], last) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return buf.Bytes(), nil | ||||||
|  | } | ||||||
							
								
								
									
										307
									
								
								vendor/github.com/Microsoft/go-winio/file.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										307
									
								
								vendor/github.com/Microsoft/go-winio/file.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,307 @@ | |||||||
|  | // +build windows | ||||||
|  |  | ||||||
|  | package winio | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"errors" | ||||||
|  | 	"io" | ||||||
|  | 	"runtime" | ||||||
|  | 	"sync" | ||||||
|  | 	"sync/atomic" | ||||||
|  | 	"syscall" | ||||||
|  | 	"time" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | //sys cancelIoEx(file syscall.Handle, o *syscall.Overlapped) (err error) = CancelIoEx | ||||||
|  | //sys createIoCompletionPort(file syscall.Handle, port syscall.Handle, key uintptr, threadCount uint32) (newport syscall.Handle, err error) = CreateIoCompletionPort | ||||||
|  | //sys getQueuedCompletionStatus(port syscall.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) = GetQueuedCompletionStatus | ||||||
|  | //sys setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err error) = SetFileCompletionNotificationModes | ||||||
|  |  | ||||||
|  | type atomicBool int32 | ||||||
|  |  | ||||||
|  | func (b *atomicBool) isSet() bool { return atomic.LoadInt32((*int32)(b)) != 0 } | ||||||
|  | func (b *atomicBool) setFalse()   { atomic.StoreInt32((*int32)(b), 0) } | ||||||
|  | func (b *atomicBool) setTrue()    { atomic.StoreInt32((*int32)(b), 1) } | ||||||
|  | func (b *atomicBool) swap(new bool) bool { | ||||||
|  | 	var newInt int32 | ||||||
|  | 	if new { | ||||||
|  | 		newInt = 1 | ||||||
|  | 	} | ||||||
|  | 	return atomic.SwapInt32((*int32)(b), newInt) == 1 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	cFILE_SKIP_COMPLETION_PORT_ON_SUCCESS = 1 | ||||||
|  | 	cFILE_SKIP_SET_EVENT_ON_HANDLE        = 2 | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | var ( | ||||||
|  | 	ErrFileClosed = errors.New("file has already been closed") | ||||||
|  | 	ErrTimeout    = &timeoutError{} | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type timeoutError struct{} | ||||||
|  |  | ||||||
|  | func (e *timeoutError) Error() string   { return "i/o timeout" } | ||||||
|  | func (e *timeoutError) Timeout() bool   { return true } | ||||||
|  | func (e *timeoutError) Temporary() bool { return true } | ||||||
|  |  | ||||||
|  | type timeoutChan chan struct{} | ||||||
|  |  | ||||||
|  | var ioInitOnce sync.Once | ||||||
|  | var ioCompletionPort syscall.Handle | ||||||
|  |  | ||||||
|  | // ioResult contains the result of an asynchronous IO operation | ||||||
|  | type ioResult struct { | ||||||
|  | 	bytes uint32 | ||||||
|  | 	err   error | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ioOperation represents an outstanding asynchronous Win32 IO | ||||||
|  | type ioOperation struct { | ||||||
|  | 	o  syscall.Overlapped | ||||||
|  | 	ch chan ioResult | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func initIo() { | ||||||
|  | 	h, err := createIoCompletionPort(syscall.InvalidHandle, 0, 0, 0xffffffff) | ||||||
|  | 	if err != nil { | ||||||
|  | 		panic(err) | ||||||
|  | 	} | ||||||
|  | 	ioCompletionPort = h | ||||||
|  | 	go ioCompletionProcessor(h) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // win32File implements Reader, Writer, and Closer on a Win32 handle without blocking in a syscall. | ||||||
|  | // It takes ownership of this handle and will close it if it is garbage collected. | ||||||
|  | type win32File struct { | ||||||
|  | 	handle        syscall.Handle | ||||||
|  | 	wg            sync.WaitGroup | ||||||
|  | 	wgLock        sync.RWMutex | ||||||
|  | 	closing       atomicBool | ||||||
|  | 	readDeadline  deadlineHandler | ||||||
|  | 	writeDeadline deadlineHandler | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type deadlineHandler struct { | ||||||
|  | 	setLock     sync.Mutex | ||||||
|  | 	channel     timeoutChan | ||||||
|  | 	channelLock sync.RWMutex | ||||||
|  | 	timer       *time.Timer | ||||||
|  | 	timedout    atomicBool | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // makeWin32File makes a new win32File from an existing file handle | ||||||
|  | func makeWin32File(h syscall.Handle) (*win32File, error) { | ||||||
|  | 	f := &win32File{handle: h} | ||||||
|  | 	ioInitOnce.Do(initIo) | ||||||
|  | 	_, err := createIoCompletionPort(h, ioCompletionPort, 0, 0xffffffff) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	err = setFileCompletionNotificationModes(h, cFILE_SKIP_COMPLETION_PORT_ON_SUCCESS|cFILE_SKIP_SET_EVENT_ON_HANDLE) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	f.readDeadline.channel = make(timeoutChan) | ||||||
|  | 	f.writeDeadline.channel = make(timeoutChan) | ||||||
|  | 	return f, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func MakeOpenFile(h syscall.Handle) (io.ReadWriteCloser, error) { | ||||||
|  | 	return makeWin32File(h) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // closeHandle closes the resources associated with a Win32 handle | ||||||
|  | func (f *win32File) closeHandle() { | ||||||
|  | 	f.wgLock.Lock() | ||||||
|  | 	// Atomically set that we are closing, releasing the resources only once. | ||||||
|  | 	if !f.closing.swap(true) { | ||||||
|  | 		f.wgLock.Unlock() | ||||||
|  | 		// cancel all IO and wait for it to complete | ||||||
|  | 		cancelIoEx(f.handle, nil) | ||||||
|  | 		f.wg.Wait() | ||||||
|  | 		// at this point, no new IO can start | ||||||
|  | 		syscall.Close(f.handle) | ||||||
|  | 		f.handle = 0 | ||||||
|  | 	} else { | ||||||
|  | 		f.wgLock.Unlock() | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Close closes a win32File. | ||||||
|  | func (f *win32File) Close() error { | ||||||
|  | 	f.closeHandle() | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // prepareIo prepares for a new IO operation. | ||||||
|  | // The caller must call f.wg.Done() when the IO is finished, prior to Close() returning. | ||||||
|  | func (f *win32File) prepareIo() (*ioOperation, error) { | ||||||
|  | 	f.wgLock.RLock() | ||||||
|  | 	if f.closing.isSet() { | ||||||
|  | 		f.wgLock.RUnlock() | ||||||
|  | 		return nil, ErrFileClosed | ||||||
|  | 	} | ||||||
|  | 	f.wg.Add(1) | ||||||
|  | 	f.wgLock.RUnlock() | ||||||
|  | 	c := &ioOperation{} | ||||||
|  | 	c.ch = make(chan ioResult) | ||||||
|  | 	return c, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ioCompletionProcessor processes completed async IOs forever | ||||||
|  | func ioCompletionProcessor(h syscall.Handle) { | ||||||
|  | 	for { | ||||||
|  | 		var bytes uint32 | ||||||
|  | 		var key uintptr | ||||||
|  | 		var op *ioOperation | ||||||
|  | 		err := getQueuedCompletionStatus(h, &bytes, &key, &op, syscall.INFINITE) | ||||||
|  | 		if op == nil { | ||||||
|  | 			panic(err) | ||||||
|  | 		} | ||||||
|  | 		op.ch <- ioResult{bytes, err} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // asyncIo processes the return value from ReadFile or WriteFile, blocking until | ||||||
|  | // the operation has actually completed. | ||||||
|  | func (f *win32File) asyncIo(c *ioOperation, d *deadlineHandler, bytes uint32, err error) (int, error) { | ||||||
|  | 	if err != syscall.ERROR_IO_PENDING { | ||||||
|  | 		return int(bytes), err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if f.closing.isSet() { | ||||||
|  | 		cancelIoEx(f.handle, &c.o) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var timeout timeoutChan | ||||||
|  | 	if d != nil { | ||||||
|  | 		d.channelLock.Lock() | ||||||
|  | 		timeout = d.channel | ||||||
|  | 		d.channelLock.Unlock() | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var r ioResult | ||||||
|  | 	select { | ||||||
|  | 	case r = <-c.ch: | ||||||
|  | 		err = r.err | ||||||
|  | 		if err == syscall.ERROR_OPERATION_ABORTED { | ||||||
|  | 			if f.closing.isSet() { | ||||||
|  | 				err = ErrFileClosed | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	case <-timeout: | ||||||
|  | 		cancelIoEx(f.handle, &c.o) | ||||||
|  | 		r = <-c.ch | ||||||
|  | 		err = r.err | ||||||
|  | 		if err == syscall.ERROR_OPERATION_ABORTED { | ||||||
|  | 			err = ErrTimeout | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// runtime.KeepAlive is needed, as c is passed via native | ||||||
|  | 	// code to ioCompletionProcessor, c must remain alive | ||||||
|  | 	// until the channel read is complete. | ||||||
|  | 	runtime.KeepAlive(c) | ||||||
|  | 	return int(r.bytes), err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Read reads from a file handle. | ||||||
|  | func (f *win32File) Read(b []byte) (int, error) { | ||||||
|  | 	c, err := f.prepareIo() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return 0, err | ||||||
|  | 	} | ||||||
|  | 	defer f.wg.Done() | ||||||
|  |  | ||||||
|  | 	if f.readDeadline.timedout.isSet() { | ||||||
|  | 		return 0, ErrTimeout | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var bytes uint32 | ||||||
|  | 	err = syscall.ReadFile(f.handle, b, &bytes, &c.o) | ||||||
|  | 	n, err := f.asyncIo(c, &f.readDeadline, bytes, err) | ||||||
|  | 	runtime.KeepAlive(b) | ||||||
|  |  | ||||||
|  | 	// Handle EOF conditions. | ||||||
|  | 	if err == nil && n == 0 && len(b) != 0 { | ||||||
|  | 		return 0, io.EOF | ||||||
|  | 	} else if err == syscall.ERROR_BROKEN_PIPE { | ||||||
|  | 		return 0, io.EOF | ||||||
|  | 	} else { | ||||||
|  | 		return n, err | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Write writes to a file handle. | ||||||
|  | func (f *win32File) Write(b []byte) (int, error) { | ||||||
|  | 	c, err := f.prepareIo() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return 0, err | ||||||
|  | 	} | ||||||
|  | 	defer f.wg.Done() | ||||||
|  |  | ||||||
|  | 	if f.writeDeadline.timedout.isSet() { | ||||||
|  | 		return 0, ErrTimeout | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var bytes uint32 | ||||||
|  | 	err = syscall.WriteFile(f.handle, b, &bytes, &c.o) | ||||||
|  | 	n, err := f.asyncIo(c, &f.writeDeadline, bytes, err) | ||||||
|  | 	runtime.KeepAlive(b) | ||||||
|  | 	return n, err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (f *win32File) SetReadDeadline(deadline time.Time) error { | ||||||
|  | 	return f.readDeadline.set(deadline) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (f *win32File) SetWriteDeadline(deadline time.Time) error { | ||||||
|  | 	return f.writeDeadline.set(deadline) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (f *win32File) Flush() error { | ||||||
|  | 	return syscall.FlushFileBuffers(f.handle) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (d *deadlineHandler) set(deadline time.Time) error { | ||||||
|  | 	d.setLock.Lock() | ||||||
|  | 	defer d.setLock.Unlock() | ||||||
|  |  | ||||||
|  | 	if d.timer != nil { | ||||||
|  | 		if !d.timer.Stop() { | ||||||
|  | 			<-d.channel | ||||||
|  | 		} | ||||||
|  | 		d.timer = nil | ||||||
|  | 	} | ||||||
|  | 	d.timedout.setFalse() | ||||||
|  |  | ||||||
|  | 	select { | ||||||
|  | 	case <-d.channel: | ||||||
|  | 		d.channelLock.Lock() | ||||||
|  | 		d.channel = make(chan struct{}) | ||||||
|  | 		d.channelLock.Unlock() | ||||||
|  | 	default: | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if deadline.IsZero() { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	timeoutIO := func() { | ||||||
|  | 		d.timedout.setTrue() | ||||||
|  | 		close(d.channel) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	now := time.Now() | ||||||
|  | 	duration := deadline.Sub(now) | ||||||
|  | 	if deadline.After(now) { | ||||||
|  | 		// Deadline is in the future, set a timer to wait | ||||||
|  | 		d.timer = time.AfterFunc(duration, timeoutIO) | ||||||
|  | 	} else { | ||||||
|  | 		// Deadline is in the past. Cancel all pending IO now. | ||||||
|  | 		timeoutIO() | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
							
								
								
									
										61
									
								
								vendor/github.com/Microsoft/go-winio/fileinfo.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								vendor/github.com/Microsoft/go-winio/fileinfo.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,61 @@ | |||||||
|  | // +build windows | ||||||
|  |  | ||||||
|  | package winio | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"os" | ||||||
|  | 	"runtime" | ||||||
|  | 	"syscall" | ||||||
|  | 	"unsafe" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | //sys getFileInformationByHandleEx(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) = GetFileInformationByHandleEx | ||||||
|  | //sys setFileInformationByHandle(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) = SetFileInformationByHandle | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	fileBasicInfo = 0 | ||||||
|  | 	fileIDInfo    = 0x12 | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // FileBasicInfo contains file access time and file attributes information. | ||||||
|  | type FileBasicInfo struct { | ||||||
|  | 	CreationTime, LastAccessTime, LastWriteTime, ChangeTime syscall.Filetime | ||||||
|  | 	FileAttributes                                          uint32 | ||||||
|  | 	pad                                                     uint32 // padding | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // GetFileBasicInfo retrieves times and attributes for a file. | ||||||
|  | func GetFileBasicInfo(f *os.File) (*FileBasicInfo, error) { | ||||||
|  | 	bi := &FileBasicInfo{} | ||||||
|  | 	if err := getFileInformationByHandleEx(syscall.Handle(f.Fd()), fileBasicInfo, (*byte)(unsafe.Pointer(bi)), uint32(unsafe.Sizeof(*bi))); err != nil { | ||||||
|  | 		return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err} | ||||||
|  | 	} | ||||||
|  | 	runtime.KeepAlive(f) | ||||||
|  | 	return bi, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // SetFileBasicInfo sets times and attributes for a file. | ||||||
|  | func SetFileBasicInfo(f *os.File, bi *FileBasicInfo) error { | ||||||
|  | 	if err := setFileInformationByHandle(syscall.Handle(f.Fd()), fileBasicInfo, (*byte)(unsafe.Pointer(bi)), uint32(unsafe.Sizeof(*bi))); err != nil { | ||||||
|  | 		return &os.PathError{Op: "SetFileInformationByHandle", Path: f.Name(), Err: err} | ||||||
|  | 	} | ||||||
|  | 	runtime.KeepAlive(f) | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // FileIDInfo contains the volume serial number and file ID for a file. This pair should be | ||||||
|  | // unique on a system. | ||||||
|  | type FileIDInfo struct { | ||||||
|  | 	VolumeSerialNumber uint64 | ||||||
|  | 	FileID             [16]byte | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // GetFileID retrieves the unique (volume, file ID) pair for a file. | ||||||
|  | func GetFileID(f *os.File) (*FileIDInfo, error) { | ||||||
|  | 	fileID := &FileIDInfo{} | ||||||
|  | 	if err := getFileInformationByHandleEx(syscall.Handle(f.Fd()), fileIDInfo, (*byte)(unsafe.Pointer(fileID)), uint32(unsafe.Sizeof(*fileID))); err != nil { | ||||||
|  | 		return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err} | ||||||
|  | 	} | ||||||
|  | 	runtime.KeepAlive(f) | ||||||
|  | 	return fileID, nil | ||||||
|  | } | ||||||
							
								
								
									
										421
									
								
								vendor/github.com/Microsoft/go-winio/pipe.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										421
									
								
								vendor/github.com/Microsoft/go-winio/pipe.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,421 @@ | |||||||
|  | // +build windows | ||||||
|  |  | ||||||
|  | package winio | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"errors" | ||||||
|  | 	"io" | ||||||
|  | 	"net" | ||||||
|  | 	"os" | ||||||
|  | 	"syscall" | ||||||
|  | 	"time" | ||||||
|  | 	"unsafe" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | //sys connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) = ConnectNamedPipe | ||||||
|  | //sys createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *syscall.SecurityAttributes) (handle syscall.Handle, err error)  [failretval==syscall.InvalidHandle] = CreateNamedPipeW | ||||||
|  | //sys createFile(name string, access uint32, mode uint32, sa *syscall.SecurityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) [failretval==syscall.InvalidHandle] = CreateFileW | ||||||
|  | //sys getNamedPipeInfo(pipe syscall.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) = GetNamedPipeInfo | ||||||
|  | //sys getNamedPipeHandleState(pipe syscall.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) = GetNamedPipeHandleStateW | ||||||
|  | //sys localAlloc(uFlags uint32, length uint32) (ptr uintptr) = LocalAlloc | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	cERROR_PIPE_BUSY      = syscall.Errno(231) | ||||||
|  | 	cERROR_NO_DATA        = syscall.Errno(232) | ||||||
|  | 	cERROR_PIPE_CONNECTED = syscall.Errno(535) | ||||||
|  | 	cERROR_SEM_TIMEOUT    = syscall.Errno(121) | ||||||
|  |  | ||||||
|  | 	cPIPE_ACCESS_DUPLEX            = 0x3 | ||||||
|  | 	cFILE_FLAG_FIRST_PIPE_INSTANCE = 0x80000 | ||||||
|  | 	cSECURITY_SQOS_PRESENT         = 0x100000 | ||||||
|  | 	cSECURITY_ANONYMOUS            = 0 | ||||||
|  |  | ||||||
|  | 	cPIPE_REJECT_REMOTE_CLIENTS = 0x8 | ||||||
|  |  | ||||||
|  | 	cPIPE_UNLIMITED_INSTANCES = 255 | ||||||
|  |  | ||||||
|  | 	cNMPWAIT_USE_DEFAULT_WAIT = 0 | ||||||
|  | 	cNMPWAIT_NOWAIT           = 1 | ||||||
|  |  | ||||||
|  | 	cPIPE_TYPE_MESSAGE = 4 | ||||||
|  |  | ||||||
|  | 	cPIPE_READMODE_MESSAGE = 2 | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | var ( | ||||||
|  | 	// ErrPipeListenerClosed is returned for pipe operations on listeners that have been closed. | ||||||
|  | 	// This error should match net.errClosing since docker takes a dependency on its text. | ||||||
|  | 	ErrPipeListenerClosed = errors.New("use of closed network connection") | ||||||
|  |  | ||||||
|  | 	errPipeWriteClosed = errors.New("pipe has been closed for write") | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type win32Pipe struct { | ||||||
|  | 	*win32File | ||||||
|  | 	path string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type win32MessageBytePipe struct { | ||||||
|  | 	win32Pipe | ||||||
|  | 	writeClosed bool | ||||||
|  | 	readEOF     bool | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type pipeAddress string | ||||||
|  |  | ||||||
|  | func (f *win32Pipe) LocalAddr() net.Addr { | ||||||
|  | 	return pipeAddress(f.path) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (f *win32Pipe) RemoteAddr() net.Addr { | ||||||
|  | 	return pipeAddress(f.path) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (f *win32Pipe) SetDeadline(t time.Time) error { | ||||||
|  | 	f.SetReadDeadline(t) | ||||||
|  | 	f.SetWriteDeadline(t) | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // CloseWrite closes the write side of a message pipe in byte mode. | ||||||
|  | func (f *win32MessageBytePipe) CloseWrite() error { | ||||||
|  | 	if f.writeClosed { | ||||||
|  | 		return errPipeWriteClosed | ||||||
|  | 	} | ||||||
|  | 	err := f.win32File.Flush() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	_, err = f.win32File.Write(nil) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	f.writeClosed = true | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Write writes bytes to a message pipe in byte mode. Zero-byte writes are ignored, since | ||||||
|  | // they are used to implement CloseWrite(). | ||||||
|  | func (f *win32MessageBytePipe) Write(b []byte) (int, error) { | ||||||
|  | 	if f.writeClosed { | ||||||
|  | 		return 0, errPipeWriteClosed | ||||||
|  | 	} | ||||||
|  | 	if len(b) == 0 { | ||||||
|  | 		return 0, nil | ||||||
|  | 	} | ||||||
|  | 	return f.win32File.Write(b) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Read reads bytes from a message pipe in byte mode. A read of a zero-byte message on a message | ||||||
|  | // mode pipe will return io.EOF, as will all subsequent reads. | ||||||
|  | func (f *win32MessageBytePipe) Read(b []byte) (int, error) { | ||||||
|  | 	if f.readEOF { | ||||||
|  | 		return 0, io.EOF | ||||||
|  | 	} | ||||||
|  | 	n, err := f.win32File.Read(b) | ||||||
|  | 	if err == io.EOF { | ||||||
|  | 		// If this was the result of a zero-byte read, then | ||||||
|  | 		// it is possible that the read was due to a zero-size | ||||||
|  | 		// message. Since we are simulating CloseWrite with a | ||||||
|  | 		// zero-byte message, ensure that all future Read() calls | ||||||
|  | 		// also return EOF. | ||||||
|  | 		f.readEOF = true | ||||||
|  | 	} else if err == syscall.ERROR_MORE_DATA { | ||||||
|  | 		// ERROR_MORE_DATA indicates that the pipe's read mode is message mode | ||||||
|  | 		// and the message still has more bytes. Treat this as a success, since | ||||||
|  | 		// this package presents all named pipes as byte streams. | ||||||
|  | 		err = nil | ||||||
|  | 	} | ||||||
|  | 	return n, err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (s pipeAddress) Network() string { | ||||||
|  | 	return "pipe" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (s pipeAddress) String() string { | ||||||
|  | 	return string(s) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // DialPipe connects to a named pipe by path, timing out if the connection | ||||||
|  | // takes longer than the specified duration. If timeout is nil, then we use | ||||||
|  | // a default timeout of 5 seconds.  (We do not use WaitNamedPipe.) | ||||||
|  | func DialPipe(path string, timeout *time.Duration) (net.Conn, error) { | ||||||
|  | 	var absTimeout time.Time | ||||||
|  | 	if timeout != nil { | ||||||
|  | 		absTimeout = time.Now().Add(*timeout) | ||||||
|  | 	} else { | ||||||
|  | 		absTimeout = time.Now().Add(time.Second * 2) | ||||||
|  | 	} | ||||||
|  | 	var err error | ||||||
|  | 	var h syscall.Handle | ||||||
|  | 	for { | ||||||
|  | 		h, err = createFile(path, syscall.GENERIC_READ|syscall.GENERIC_WRITE, 0, nil, syscall.OPEN_EXISTING, syscall.FILE_FLAG_OVERLAPPED|cSECURITY_SQOS_PRESENT|cSECURITY_ANONYMOUS, 0) | ||||||
|  | 		if err != cERROR_PIPE_BUSY { | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 		if time.Now().After(absTimeout) { | ||||||
|  | 			return nil, ErrTimeout | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// Wait 10 msec and try again. This is a rather simplistic | ||||||
|  | 		// view, as we always try each 10 milliseconds. | ||||||
|  | 		time.Sleep(time.Millisecond * 10) | ||||||
|  | 	} | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, &os.PathError{Op: "open", Path: path, Err: err} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var flags uint32 | ||||||
|  | 	err = getNamedPipeInfo(h, &flags, nil, nil, nil) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	f, err := makeWin32File(h) | ||||||
|  | 	if err != nil { | ||||||
|  | 		syscall.Close(h) | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// If the pipe is in message mode, return a message byte pipe, which | ||||||
|  | 	// supports CloseWrite(). | ||||||
|  | 	if flags&cPIPE_TYPE_MESSAGE != 0 { | ||||||
|  | 		return &win32MessageBytePipe{ | ||||||
|  | 			win32Pipe: win32Pipe{win32File: f, path: path}, | ||||||
|  | 		}, nil | ||||||
|  | 	} | ||||||
|  | 	return &win32Pipe{win32File: f, path: path}, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type acceptResponse struct { | ||||||
|  | 	f   *win32File | ||||||
|  | 	err error | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type win32PipeListener struct { | ||||||
|  | 	firstHandle        syscall.Handle | ||||||
|  | 	path               string | ||||||
|  | 	securityDescriptor []byte | ||||||
|  | 	config             PipeConfig | ||||||
|  | 	acceptCh           chan (chan acceptResponse) | ||||||
|  | 	closeCh            chan int | ||||||
|  | 	doneCh             chan int | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func makeServerPipeHandle(path string, securityDescriptor []byte, c *PipeConfig, first bool) (syscall.Handle, error) { | ||||||
|  | 	var flags uint32 = cPIPE_ACCESS_DUPLEX | syscall.FILE_FLAG_OVERLAPPED | ||||||
|  | 	if first { | ||||||
|  | 		flags |= cFILE_FLAG_FIRST_PIPE_INSTANCE | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var mode uint32 = cPIPE_REJECT_REMOTE_CLIENTS | ||||||
|  | 	if c.MessageMode { | ||||||
|  | 		mode |= cPIPE_TYPE_MESSAGE | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	sa := &syscall.SecurityAttributes{} | ||||||
|  | 	sa.Length = uint32(unsafe.Sizeof(*sa)) | ||||||
|  | 	if securityDescriptor != nil { | ||||||
|  | 		len := uint32(len(securityDescriptor)) | ||||||
|  | 		sa.SecurityDescriptor = localAlloc(0, len) | ||||||
|  | 		defer localFree(sa.SecurityDescriptor) | ||||||
|  | 		copy((*[0xffff]byte)(unsafe.Pointer(sa.SecurityDescriptor))[:], securityDescriptor) | ||||||
|  | 	} | ||||||
|  | 	h, err := createNamedPipe(path, flags, mode, cPIPE_UNLIMITED_INSTANCES, uint32(c.OutputBufferSize), uint32(c.InputBufferSize), 0, sa) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return 0, &os.PathError{Op: "open", Path: path, Err: err} | ||||||
|  | 	} | ||||||
|  | 	return h, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (l *win32PipeListener) makeServerPipe() (*win32File, error) { | ||||||
|  | 	h, err := makeServerPipeHandle(l.path, l.securityDescriptor, &l.config, false) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	f, err := makeWin32File(h) | ||||||
|  | 	if err != nil { | ||||||
|  | 		syscall.Close(h) | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return f, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (l *win32PipeListener) makeConnectedServerPipe() (*win32File, error) { | ||||||
|  | 	p, err := l.makeServerPipe() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Wait for the client to connect. | ||||||
|  | 	ch := make(chan error) | ||||||
|  | 	go func(p *win32File) { | ||||||
|  | 		ch <- connectPipe(p) | ||||||
|  | 	}(p) | ||||||
|  |  | ||||||
|  | 	select { | ||||||
|  | 	case err = <-ch: | ||||||
|  | 		if err != nil { | ||||||
|  | 			p.Close() | ||||||
|  | 			p = nil | ||||||
|  | 		} | ||||||
|  | 	case <-l.closeCh: | ||||||
|  | 		// Abort the connect request by closing the handle. | ||||||
|  | 		p.Close() | ||||||
|  | 		p = nil | ||||||
|  | 		err = <-ch | ||||||
|  | 		if err == nil || err == ErrFileClosed { | ||||||
|  | 			err = ErrPipeListenerClosed | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return p, err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (l *win32PipeListener) listenerRoutine() { | ||||||
|  | 	closed := false | ||||||
|  | 	for !closed { | ||||||
|  | 		select { | ||||||
|  | 		case <-l.closeCh: | ||||||
|  | 			closed = true | ||||||
|  | 		case responseCh := <-l.acceptCh: | ||||||
|  | 			var ( | ||||||
|  | 				p   *win32File | ||||||
|  | 				err error | ||||||
|  | 			) | ||||||
|  | 			for { | ||||||
|  | 				p, err = l.makeConnectedServerPipe() | ||||||
|  | 				// If the connection was immediately closed by the client, try | ||||||
|  | 				// again. | ||||||
|  | 				if err != cERROR_NO_DATA { | ||||||
|  | 					break | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			responseCh <- acceptResponse{p, err} | ||||||
|  | 			closed = err == ErrPipeListenerClosed | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	syscall.Close(l.firstHandle) | ||||||
|  | 	l.firstHandle = 0 | ||||||
|  | 	// Notify Close() and Accept() callers that the handle has been closed. | ||||||
|  | 	close(l.doneCh) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // PipeConfig contain configuration for the pipe listener. | ||||||
|  | type PipeConfig struct { | ||||||
|  | 	// SecurityDescriptor contains a Windows security descriptor in SDDL format. | ||||||
|  | 	SecurityDescriptor string | ||||||
|  |  | ||||||
|  | 	// MessageMode determines whether the pipe is in byte or message mode. In either | ||||||
|  | 	// case the pipe is read in byte mode by default. The only practical difference in | ||||||
|  | 	// this implementation is that CloseWrite() is only supported for message mode pipes; | ||||||
|  | 	// CloseWrite() is implemented as a zero-byte write, but zero-byte writes are only | ||||||
|  | 	// transferred to the reader (and returned as io.EOF in this implementation) | ||||||
|  | 	// when the pipe is in message mode. | ||||||
|  | 	MessageMode bool | ||||||
|  |  | ||||||
|  | 	// InputBufferSize specifies the size the input buffer, in bytes. | ||||||
|  | 	InputBufferSize int32 | ||||||
|  |  | ||||||
|  | 	// OutputBufferSize specifies the size the input buffer, in bytes. | ||||||
|  | 	OutputBufferSize int32 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ListenPipe creates a listener on a Windows named pipe path, e.g. \\.\pipe\mypipe. | ||||||
|  | // The pipe must not already exist. | ||||||
|  | func ListenPipe(path string, c *PipeConfig) (net.Listener, error) { | ||||||
|  | 	var ( | ||||||
|  | 		sd  []byte | ||||||
|  | 		err error | ||||||
|  | 	) | ||||||
|  | 	if c == nil { | ||||||
|  | 		c = &PipeConfig{} | ||||||
|  | 	} | ||||||
|  | 	if c.SecurityDescriptor != "" { | ||||||
|  | 		sd, err = SddlToSecurityDescriptor(c.SecurityDescriptor) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	h, err := makeServerPipeHandle(path, sd, c, true) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	// Create a client handle and connect it.  This results in the pipe | ||||||
|  | 	// instance always existing, so that clients see ERROR_PIPE_BUSY | ||||||
|  | 	// rather than ERROR_FILE_NOT_FOUND.  This ties the first instance | ||||||
|  | 	// up so that no other instances can be used.  This would have been | ||||||
|  | 	// cleaner if the Win32 API matched CreateFile with ConnectNamedPipe | ||||||
|  | 	// instead of CreateNamedPipe.  (Apparently created named pipes are | ||||||
|  | 	// considered to be in listening state regardless of whether any | ||||||
|  | 	// active calls to ConnectNamedPipe are outstanding.) | ||||||
|  | 	h2, err := createFile(path, 0, 0, nil, syscall.OPEN_EXISTING, cSECURITY_SQOS_PRESENT|cSECURITY_ANONYMOUS, 0) | ||||||
|  | 	if err != nil { | ||||||
|  | 		syscall.Close(h) | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	// Close the client handle. The server side of the instance will | ||||||
|  | 	// still be busy, leading to ERROR_PIPE_BUSY instead of | ||||||
|  | 	// ERROR_NOT_FOUND, as long as we don't close the server handle, | ||||||
|  | 	// or disconnect the client with DisconnectNamedPipe. | ||||||
|  | 	syscall.Close(h2) | ||||||
|  | 	l := &win32PipeListener{ | ||||||
|  | 		firstHandle:        h, | ||||||
|  | 		path:               path, | ||||||
|  | 		securityDescriptor: sd, | ||||||
|  | 		config:             *c, | ||||||
|  | 		acceptCh:           make(chan (chan acceptResponse)), | ||||||
|  | 		closeCh:            make(chan int), | ||||||
|  | 		doneCh:             make(chan int), | ||||||
|  | 	} | ||||||
|  | 	go l.listenerRoutine() | ||||||
|  | 	return l, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func connectPipe(p *win32File) error { | ||||||
|  | 	c, err := p.prepareIo() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	defer p.wg.Done() | ||||||
|  |  | ||||||
|  | 	err = connectNamedPipe(p.handle, &c.o) | ||||||
|  | 	_, err = p.asyncIo(c, nil, 0, err) | ||||||
|  | 	if err != nil && err != cERROR_PIPE_CONNECTED { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (l *win32PipeListener) Accept() (net.Conn, error) { | ||||||
|  | 	ch := make(chan acceptResponse) | ||||||
|  | 	select { | ||||||
|  | 	case l.acceptCh <- ch: | ||||||
|  | 		response := <-ch | ||||||
|  | 		err := response.err | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 		if l.config.MessageMode { | ||||||
|  | 			return &win32MessageBytePipe{ | ||||||
|  | 				win32Pipe: win32Pipe{win32File: response.f, path: l.path}, | ||||||
|  | 			}, nil | ||||||
|  | 		} | ||||||
|  | 		return &win32Pipe{win32File: response.f, path: l.path}, nil | ||||||
|  | 	case <-l.doneCh: | ||||||
|  | 		return nil, ErrPipeListenerClosed | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (l *win32PipeListener) Close() error { | ||||||
|  | 	select { | ||||||
|  | 	case l.closeCh <- 1: | ||||||
|  | 		<-l.doneCh | ||||||
|  | 	case <-l.doneCh: | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (l *win32PipeListener) Addr() net.Addr { | ||||||
|  | 	return pipeAddress(l.path) | ||||||
|  | } | ||||||
							
								
								
									
										202
									
								
								vendor/github.com/Microsoft/go-winio/privilege.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										202
									
								
								vendor/github.com/Microsoft/go-winio/privilege.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,202 @@ | |||||||
|  | // +build windows | ||||||
|  |  | ||||||
|  | package winio | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"bytes" | ||||||
|  | 	"encoding/binary" | ||||||
|  | 	"fmt" | ||||||
|  | 	"runtime" | ||||||
|  | 	"sync" | ||||||
|  | 	"syscall" | ||||||
|  | 	"unicode/utf16" | ||||||
|  |  | ||||||
|  | 	"golang.org/x/sys/windows" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | //sys adjustTokenPrivileges(token windows.Token, releaseAll bool, input *byte, outputSize uint32, output *byte, requiredSize *uint32) (success bool, err error) [true] = advapi32.AdjustTokenPrivileges | ||||||
|  | //sys impersonateSelf(level uint32) (err error) = advapi32.ImpersonateSelf | ||||||
|  | //sys revertToSelf() (err error) = advapi32.RevertToSelf | ||||||
|  | //sys openThreadToken(thread syscall.Handle, accessMask uint32, openAsSelf bool, token *windows.Token) (err error) = advapi32.OpenThreadToken | ||||||
|  | //sys getCurrentThread() (h syscall.Handle) = GetCurrentThread | ||||||
|  | //sys lookupPrivilegeValue(systemName string, name string, luid *uint64) (err error) = advapi32.LookupPrivilegeValueW | ||||||
|  | //sys lookupPrivilegeName(systemName string, luid *uint64, buffer *uint16, size *uint32) (err error) = advapi32.LookupPrivilegeNameW | ||||||
|  | //sys lookupPrivilegeDisplayName(systemName string, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) = advapi32.LookupPrivilegeDisplayNameW | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	SE_PRIVILEGE_ENABLED = 2 | ||||||
|  |  | ||||||
|  | 	ERROR_NOT_ALL_ASSIGNED syscall.Errno = 1300 | ||||||
|  |  | ||||||
|  | 	SeBackupPrivilege  = "SeBackupPrivilege" | ||||||
|  | 	SeRestorePrivilege = "SeRestorePrivilege" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	securityAnonymous = iota | ||||||
|  | 	securityIdentification | ||||||
|  | 	securityImpersonation | ||||||
|  | 	securityDelegation | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | var ( | ||||||
|  | 	privNames     = make(map[string]uint64) | ||||||
|  | 	privNameMutex sync.Mutex | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // PrivilegeError represents an error enabling privileges. | ||||||
|  | type PrivilegeError struct { | ||||||
|  | 	privileges []uint64 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (e *PrivilegeError) Error() string { | ||||||
|  | 	s := "" | ||||||
|  | 	if len(e.privileges) > 1 { | ||||||
|  | 		s = "Could not enable privileges " | ||||||
|  | 	} else { | ||||||
|  | 		s = "Could not enable privilege " | ||||||
|  | 	} | ||||||
|  | 	for i, p := range e.privileges { | ||||||
|  | 		if i != 0 { | ||||||
|  | 			s += ", " | ||||||
|  | 		} | ||||||
|  | 		s += `"` | ||||||
|  | 		s += getPrivilegeName(p) | ||||||
|  | 		s += `"` | ||||||
|  | 	} | ||||||
|  | 	return s | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // RunWithPrivilege enables a single privilege for a function call. | ||||||
|  | func RunWithPrivilege(name string, fn func() error) error { | ||||||
|  | 	return RunWithPrivileges([]string{name}, fn) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // RunWithPrivileges enables privileges for a function call. | ||||||
|  | func RunWithPrivileges(names []string, fn func() error) error { | ||||||
|  | 	privileges, err := mapPrivileges(names) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	runtime.LockOSThread() | ||||||
|  | 	defer runtime.UnlockOSThread() | ||||||
|  | 	token, err := newThreadToken() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	defer releaseThreadToken(token) | ||||||
|  | 	err = adjustPrivileges(token, privileges, SE_PRIVILEGE_ENABLED) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	return fn() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func mapPrivileges(names []string) ([]uint64, error) { | ||||||
|  | 	var privileges []uint64 | ||||||
|  | 	privNameMutex.Lock() | ||||||
|  | 	defer privNameMutex.Unlock() | ||||||
|  | 	for _, name := range names { | ||||||
|  | 		p, ok := privNames[name] | ||||||
|  | 		if !ok { | ||||||
|  | 			err := lookupPrivilegeValue("", name, &p) | ||||||
|  | 			if err != nil { | ||||||
|  | 				return nil, err | ||||||
|  | 			} | ||||||
|  | 			privNames[name] = p | ||||||
|  | 		} | ||||||
|  | 		privileges = append(privileges, p) | ||||||
|  | 	} | ||||||
|  | 	return privileges, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // EnableProcessPrivileges enables privileges globally for the process. | ||||||
|  | func EnableProcessPrivileges(names []string) error { | ||||||
|  | 	return enableDisableProcessPrivilege(names, SE_PRIVILEGE_ENABLED) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // DisableProcessPrivileges disables privileges globally for the process. | ||||||
|  | func DisableProcessPrivileges(names []string) error { | ||||||
|  | 	return enableDisableProcessPrivilege(names, 0) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func enableDisableProcessPrivilege(names []string, action uint32) error { | ||||||
|  | 	privileges, err := mapPrivileges(names) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	p, _ := windows.GetCurrentProcess() | ||||||
|  | 	var token windows.Token | ||||||
|  | 	err = windows.OpenProcessToken(p, windows.TOKEN_ADJUST_PRIVILEGES|windows.TOKEN_QUERY, &token) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	defer token.Close() | ||||||
|  | 	return adjustPrivileges(token, privileges, action) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func adjustPrivileges(token windows.Token, privileges []uint64, action uint32) error { | ||||||
|  | 	var b bytes.Buffer | ||||||
|  | 	binary.Write(&b, binary.LittleEndian, uint32(len(privileges))) | ||||||
|  | 	for _, p := range privileges { | ||||||
|  | 		binary.Write(&b, binary.LittleEndian, p) | ||||||
|  | 		binary.Write(&b, binary.LittleEndian, action) | ||||||
|  | 	} | ||||||
|  | 	prevState := make([]byte, b.Len()) | ||||||
|  | 	reqSize := uint32(0) | ||||||
|  | 	success, err := adjustTokenPrivileges(token, false, &b.Bytes()[0], uint32(len(prevState)), &prevState[0], &reqSize) | ||||||
|  | 	if !success { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	if err == ERROR_NOT_ALL_ASSIGNED { | ||||||
|  | 		return &PrivilegeError{privileges} | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func getPrivilegeName(luid uint64) string { | ||||||
|  | 	var nameBuffer [256]uint16 | ||||||
|  | 	bufSize := uint32(len(nameBuffer)) | ||||||
|  | 	err := lookupPrivilegeName("", &luid, &nameBuffer[0], &bufSize) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return fmt.Sprintf("<unknown privilege %d>", luid) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var displayNameBuffer [256]uint16 | ||||||
|  | 	displayBufSize := uint32(len(displayNameBuffer)) | ||||||
|  | 	var langID uint32 | ||||||
|  | 	err = lookupPrivilegeDisplayName("", &nameBuffer[0], &displayNameBuffer[0], &displayBufSize, &langID) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return fmt.Sprintf("<unknown privilege %s>", string(utf16.Decode(nameBuffer[:bufSize]))) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return string(utf16.Decode(displayNameBuffer[:displayBufSize])) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func newThreadToken() (windows.Token, error) { | ||||||
|  | 	err := impersonateSelf(securityImpersonation) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return 0, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var token windows.Token | ||||||
|  | 	err = openThreadToken(getCurrentThread(), syscall.TOKEN_ADJUST_PRIVILEGES|syscall.TOKEN_QUERY, false, &token) | ||||||
|  | 	if err != nil { | ||||||
|  | 		rerr := revertToSelf() | ||||||
|  | 		if rerr != nil { | ||||||
|  | 			panic(rerr) | ||||||
|  | 		} | ||||||
|  | 		return 0, err | ||||||
|  | 	} | ||||||
|  | 	return token, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func releaseThreadToken(h windows.Token) { | ||||||
|  | 	err := revertToSelf() | ||||||
|  | 	if err != nil { | ||||||
|  | 		panic(err) | ||||||
|  | 	} | ||||||
|  | 	h.Close() | ||||||
|  | } | ||||||
							
								
								
									
										128
									
								
								vendor/github.com/Microsoft/go-winio/reparse.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								vendor/github.com/Microsoft/go-winio/reparse.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,128 @@ | |||||||
|  | package winio | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"bytes" | ||||||
|  | 	"encoding/binary" | ||||||
|  | 	"fmt" | ||||||
|  | 	"strings" | ||||||
|  | 	"unicode/utf16" | ||||||
|  | 	"unsafe" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	reparseTagMountPoint = 0xA0000003 | ||||||
|  | 	reparseTagSymlink    = 0xA000000C | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type reparseDataBuffer struct { | ||||||
|  | 	ReparseTag           uint32 | ||||||
|  | 	ReparseDataLength    uint16 | ||||||
|  | 	Reserved             uint16 | ||||||
|  | 	SubstituteNameOffset uint16 | ||||||
|  | 	SubstituteNameLength uint16 | ||||||
|  | 	PrintNameOffset      uint16 | ||||||
|  | 	PrintNameLength      uint16 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ReparsePoint describes a Win32 symlink or mount point. | ||||||
|  | type ReparsePoint struct { | ||||||
|  | 	Target       string | ||||||
|  | 	IsMountPoint bool | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // UnsupportedReparsePointError is returned when trying to decode a non-symlink or | ||||||
|  | // mount point reparse point. | ||||||
|  | type UnsupportedReparsePointError struct { | ||||||
|  | 	Tag uint32 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (e *UnsupportedReparsePointError) Error() string { | ||||||
|  | 	return fmt.Sprintf("unsupported reparse point %x", e.Tag) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // DecodeReparsePoint decodes a Win32 REPARSE_DATA_BUFFER structure containing either a symlink | ||||||
|  | // or a mount point. | ||||||
|  | func DecodeReparsePoint(b []byte) (*ReparsePoint, error) { | ||||||
|  | 	tag := binary.LittleEndian.Uint32(b[0:4]) | ||||||
|  | 	return DecodeReparsePointData(tag, b[8:]) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func DecodeReparsePointData(tag uint32, b []byte) (*ReparsePoint, error) { | ||||||
|  | 	isMountPoint := false | ||||||
|  | 	switch tag { | ||||||
|  | 	case reparseTagMountPoint: | ||||||
|  | 		isMountPoint = true | ||||||
|  | 	case reparseTagSymlink: | ||||||
|  | 	default: | ||||||
|  | 		return nil, &UnsupportedReparsePointError{tag} | ||||||
|  | 	} | ||||||
|  | 	nameOffset := 8 + binary.LittleEndian.Uint16(b[4:6]) | ||||||
|  | 	if !isMountPoint { | ||||||
|  | 		nameOffset += 4 | ||||||
|  | 	} | ||||||
|  | 	nameLength := binary.LittleEndian.Uint16(b[6:8]) | ||||||
|  | 	name := make([]uint16, nameLength/2) | ||||||
|  | 	err := binary.Read(bytes.NewReader(b[nameOffset:nameOffset+nameLength]), binary.LittleEndian, &name) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return &ReparsePoint{string(utf16.Decode(name)), isMountPoint}, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func isDriveLetter(c byte) bool { | ||||||
|  | 	return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // EncodeReparsePoint encodes a Win32 REPARSE_DATA_BUFFER structure describing a symlink or | ||||||
|  | // mount point. | ||||||
|  | func EncodeReparsePoint(rp *ReparsePoint) []byte { | ||||||
|  | 	// Generate an NT path and determine if this is a relative path. | ||||||
|  | 	var ntTarget string | ||||||
|  | 	relative := false | ||||||
|  | 	if strings.HasPrefix(rp.Target, `\\?\`) { | ||||||
|  | 		ntTarget = `\??\` + rp.Target[4:] | ||||||
|  | 	} else if strings.HasPrefix(rp.Target, `\\`) { | ||||||
|  | 		ntTarget = `\??\UNC\` + rp.Target[2:] | ||||||
|  | 	} else if len(rp.Target) >= 2 && isDriveLetter(rp.Target[0]) && rp.Target[1] == ':' { | ||||||
|  | 		ntTarget = `\??\` + rp.Target | ||||||
|  | 	} else { | ||||||
|  | 		ntTarget = rp.Target | ||||||
|  | 		relative = true | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// The paths must be NUL-terminated even though they are counted strings. | ||||||
|  | 	target16 := utf16.Encode([]rune(rp.Target + "\x00")) | ||||||
|  | 	ntTarget16 := utf16.Encode([]rune(ntTarget + "\x00")) | ||||||
|  |  | ||||||
|  | 	size := int(unsafe.Sizeof(reparseDataBuffer{})) - 8 | ||||||
|  | 	size += len(ntTarget16)*2 + len(target16)*2 | ||||||
|  |  | ||||||
|  | 	tag := uint32(reparseTagMountPoint) | ||||||
|  | 	if !rp.IsMountPoint { | ||||||
|  | 		tag = reparseTagSymlink | ||||||
|  | 		size += 4 // Add room for symlink flags | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	data := reparseDataBuffer{ | ||||||
|  | 		ReparseTag:           tag, | ||||||
|  | 		ReparseDataLength:    uint16(size), | ||||||
|  | 		SubstituteNameOffset: 0, | ||||||
|  | 		SubstituteNameLength: uint16((len(ntTarget16) - 1) * 2), | ||||||
|  | 		PrintNameOffset:      uint16(len(ntTarget16) * 2), | ||||||
|  | 		PrintNameLength:      uint16((len(target16) - 1) * 2), | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var b bytes.Buffer | ||||||
|  | 	binary.Write(&b, binary.LittleEndian, &data) | ||||||
|  | 	if !rp.IsMountPoint { | ||||||
|  | 		flags := uint32(0) | ||||||
|  | 		if relative { | ||||||
|  | 			flags |= 1 | ||||||
|  | 		} | ||||||
|  | 		binary.Write(&b, binary.LittleEndian, flags) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	binary.Write(&b, binary.LittleEndian, ntTarget16) | ||||||
|  | 	binary.Write(&b, binary.LittleEndian, target16) | ||||||
|  | 	return b.Bytes() | ||||||
|  | } | ||||||
							
								
								
									
										98
									
								
								vendor/github.com/Microsoft/go-winio/sd.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								vendor/github.com/Microsoft/go-winio/sd.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,98 @@ | |||||||
|  | // +build windows | ||||||
|  |  | ||||||
|  | package winio | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"syscall" | ||||||
|  | 	"unsafe" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | //sys lookupAccountName(systemName *uint16, accountName string, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) = advapi32.LookupAccountNameW | ||||||
|  | //sys convertSidToStringSid(sid *byte, str **uint16) (err error) = advapi32.ConvertSidToStringSidW | ||||||
|  | //sys convertStringSecurityDescriptorToSecurityDescriptor(str string, revision uint32, sd *uintptr, size *uint32) (err error) = advapi32.ConvertStringSecurityDescriptorToSecurityDescriptorW | ||||||
|  | //sys convertSecurityDescriptorToStringSecurityDescriptor(sd *byte, revision uint32, secInfo uint32, sddl **uint16, sddlSize *uint32) (err error) = advapi32.ConvertSecurityDescriptorToStringSecurityDescriptorW | ||||||
|  | //sys localFree(mem uintptr) = LocalFree | ||||||
|  | //sys getSecurityDescriptorLength(sd uintptr) (len uint32) = advapi32.GetSecurityDescriptorLength | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	cERROR_NONE_MAPPED = syscall.Errno(1332) | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type AccountLookupError struct { | ||||||
|  | 	Name string | ||||||
|  | 	Err  error | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (e *AccountLookupError) Error() string { | ||||||
|  | 	if e.Name == "" { | ||||||
|  | 		return "lookup account: empty account name specified" | ||||||
|  | 	} | ||||||
|  | 	var s string | ||||||
|  | 	switch e.Err { | ||||||
|  | 	case cERROR_NONE_MAPPED: | ||||||
|  | 		s = "not found" | ||||||
|  | 	default: | ||||||
|  | 		s = e.Err.Error() | ||||||
|  | 	} | ||||||
|  | 	return "lookup account " + e.Name + ": " + s | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type SddlConversionError struct { | ||||||
|  | 	Sddl string | ||||||
|  | 	Err  error | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (e *SddlConversionError) Error() string { | ||||||
|  | 	return "convert " + e.Sddl + ": " + e.Err.Error() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // LookupSidByName looks up the SID of an account by name | ||||||
|  | func LookupSidByName(name string) (sid string, err error) { | ||||||
|  | 	if name == "" { | ||||||
|  | 		return "", &AccountLookupError{name, cERROR_NONE_MAPPED} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var sidSize, sidNameUse, refDomainSize uint32 | ||||||
|  | 	err = lookupAccountName(nil, name, nil, &sidSize, nil, &refDomainSize, &sidNameUse) | ||||||
|  | 	if err != nil && err != syscall.ERROR_INSUFFICIENT_BUFFER { | ||||||
|  | 		return "", &AccountLookupError{name, err} | ||||||
|  | 	} | ||||||
|  | 	sidBuffer := make([]byte, sidSize) | ||||||
|  | 	refDomainBuffer := make([]uint16, refDomainSize) | ||||||
|  | 	err = lookupAccountName(nil, name, &sidBuffer[0], &sidSize, &refDomainBuffer[0], &refDomainSize, &sidNameUse) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return "", &AccountLookupError{name, err} | ||||||
|  | 	} | ||||||
|  | 	var strBuffer *uint16 | ||||||
|  | 	err = convertSidToStringSid(&sidBuffer[0], &strBuffer) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return "", &AccountLookupError{name, err} | ||||||
|  | 	} | ||||||
|  | 	sid = syscall.UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(strBuffer))[:]) | ||||||
|  | 	localFree(uintptr(unsafe.Pointer(strBuffer))) | ||||||
|  | 	return sid, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func SddlToSecurityDescriptor(sddl string) ([]byte, error) { | ||||||
|  | 	var sdBuffer uintptr | ||||||
|  | 	err := convertStringSecurityDescriptorToSecurityDescriptor(sddl, 1, &sdBuffer, nil) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, &SddlConversionError{sddl, err} | ||||||
|  | 	} | ||||||
|  | 	defer localFree(sdBuffer) | ||||||
|  | 	sd := make([]byte, getSecurityDescriptorLength(sdBuffer)) | ||||||
|  | 	copy(sd, (*[0xffff]byte)(unsafe.Pointer(sdBuffer))[:len(sd)]) | ||||||
|  | 	return sd, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func SecurityDescriptorToSddl(sd []byte) (string, error) { | ||||||
|  | 	var sddl *uint16 | ||||||
|  | 	// The returned string length seems to including an aribtrary number of terminating NULs. | ||||||
|  | 	// Don't use it. | ||||||
|  | 	err := convertSecurityDescriptorToStringSecurityDescriptor(&sd[0], 1, 0xff, &sddl, nil) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return "", err | ||||||
|  | 	} | ||||||
|  | 	defer localFree(uintptr(unsafe.Pointer(sddl))) | ||||||
|  | 	return syscall.UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(sddl))[:]), nil | ||||||
|  | } | ||||||
							
								
								
									
										3
									
								
								vendor/github.com/Microsoft/go-winio/syscall.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								vendor/github.com/Microsoft/go-winio/syscall.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | |||||||
|  | package winio | ||||||
|  |  | ||||||
|  | //go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go file.go pipe.go sd.go fileinfo.go privilege.go backup.go | ||||||
							
								
								
									
										520
									
								
								vendor/github.com/Microsoft/go-winio/zsyscall_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										520
									
								
								vendor/github.com/Microsoft/go-winio/zsyscall_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,520 @@ | |||||||
|  | // MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT | ||||||
|  |  | ||||||
|  | package winio | ||||||
|  |  | ||||||
|  | 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 ( | ||||||
|  | 	modkernel32 = windows.NewLazySystemDLL("kernel32.dll") | ||||||
|  | 	modadvapi32 = windows.NewLazySystemDLL("advapi32.dll") | ||||||
|  |  | ||||||
|  | 	procCancelIoEx                                           = modkernel32.NewProc("CancelIoEx") | ||||||
|  | 	procCreateIoCompletionPort                               = modkernel32.NewProc("CreateIoCompletionPort") | ||||||
|  | 	procGetQueuedCompletionStatus                            = modkernel32.NewProc("GetQueuedCompletionStatus") | ||||||
|  | 	procSetFileCompletionNotificationModes                   = modkernel32.NewProc("SetFileCompletionNotificationModes") | ||||||
|  | 	procConnectNamedPipe                                     = modkernel32.NewProc("ConnectNamedPipe") | ||||||
|  | 	procCreateNamedPipeW                                     = modkernel32.NewProc("CreateNamedPipeW") | ||||||
|  | 	procCreateFileW                                          = modkernel32.NewProc("CreateFileW") | ||||||
|  | 	procWaitNamedPipeW                                       = modkernel32.NewProc("WaitNamedPipeW") | ||||||
|  | 	procGetNamedPipeInfo                                     = modkernel32.NewProc("GetNamedPipeInfo") | ||||||
|  | 	procGetNamedPipeHandleStateW                             = modkernel32.NewProc("GetNamedPipeHandleStateW") | ||||||
|  | 	procLocalAlloc                                           = modkernel32.NewProc("LocalAlloc") | ||||||
|  | 	procLookupAccountNameW                                   = modadvapi32.NewProc("LookupAccountNameW") | ||||||
|  | 	procConvertSidToStringSidW                               = modadvapi32.NewProc("ConvertSidToStringSidW") | ||||||
|  | 	procConvertStringSecurityDescriptorToSecurityDescriptorW = modadvapi32.NewProc("ConvertStringSecurityDescriptorToSecurityDescriptorW") | ||||||
|  | 	procConvertSecurityDescriptorToStringSecurityDescriptorW = modadvapi32.NewProc("ConvertSecurityDescriptorToStringSecurityDescriptorW") | ||||||
|  | 	procLocalFree                                            = modkernel32.NewProc("LocalFree") | ||||||
|  | 	procGetSecurityDescriptorLength                          = modadvapi32.NewProc("GetSecurityDescriptorLength") | ||||||
|  | 	procGetFileInformationByHandleEx                         = modkernel32.NewProc("GetFileInformationByHandleEx") | ||||||
|  | 	procSetFileInformationByHandle                           = modkernel32.NewProc("SetFileInformationByHandle") | ||||||
|  | 	procAdjustTokenPrivileges                                = modadvapi32.NewProc("AdjustTokenPrivileges") | ||||||
|  | 	procImpersonateSelf                                      = modadvapi32.NewProc("ImpersonateSelf") | ||||||
|  | 	procRevertToSelf                                         = modadvapi32.NewProc("RevertToSelf") | ||||||
|  | 	procOpenThreadToken                                      = modadvapi32.NewProc("OpenThreadToken") | ||||||
|  | 	procGetCurrentThread                                     = modkernel32.NewProc("GetCurrentThread") | ||||||
|  | 	procLookupPrivilegeValueW                                = modadvapi32.NewProc("LookupPrivilegeValueW") | ||||||
|  | 	procLookupPrivilegeNameW                                 = modadvapi32.NewProc("LookupPrivilegeNameW") | ||||||
|  | 	procLookupPrivilegeDisplayNameW                          = modadvapi32.NewProc("LookupPrivilegeDisplayNameW") | ||||||
|  | 	procBackupRead                                           = modkernel32.NewProc("BackupRead") | ||||||
|  | 	procBackupWrite                                          = modkernel32.NewProc("BackupWrite") | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func cancelIoEx(file syscall.Handle, o *syscall.Overlapped) (err error) { | ||||||
|  | 	r1, _, e1 := syscall.Syscall(procCancelIoEx.Addr(), 2, uintptr(file), uintptr(unsafe.Pointer(o)), 0) | ||||||
|  | 	if r1 == 0 { | ||||||
|  | 		if e1 != 0 { | ||||||
|  | 			err = errnoErr(e1) | ||||||
|  | 		} else { | ||||||
|  | 			err = syscall.EINVAL | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func createIoCompletionPort(file syscall.Handle, port syscall.Handle, key uintptr, threadCount uint32) (newport syscall.Handle, err error) { | ||||||
|  | 	r0, _, e1 := syscall.Syscall6(procCreateIoCompletionPort.Addr(), 4, uintptr(file), uintptr(port), uintptr(key), uintptr(threadCount), 0, 0) | ||||||
|  | 	newport = syscall.Handle(r0) | ||||||
|  | 	if newport == 0 { | ||||||
|  | 		if e1 != 0 { | ||||||
|  | 			err = errnoErr(e1) | ||||||
|  | 		} else { | ||||||
|  | 			err = syscall.EINVAL | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func getQueuedCompletionStatus(port syscall.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) { | ||||||
|  | 	r1, _, e1 := syscall.Syscall6(procGetQueuedCompletionStatus.Addr(), 5, uintptr(port), uintptr(unsafe.Pointer(bytes)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(o)), uintptr(timeout), 0) | ||||||
|  | 	if r1 == 0 { | ||||||
|  | 		if e1 != 0 { | ||||||
|  | 			err = errnoErr(e1) | ||||||
|  | 		} else { | ||||||
|  | 			err = syscall.EINVAL | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err error) { | ||||||
|  | 	r1, _, e1 := syscall.Syscall(procSetFileCompletionNotificationModes.Addr(), 2, uintptr(h), uintptr(flags), 0) | ||||||
|  | 	if r1 == 0 { | ||||||
|  | 		if e1 != 0 { | ||||||
|  | 			err = errnoErr(e1) | ||||||
|  | 		} else { | ||||||
|  | 			err = syscall.EINVAL | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) { | ||||||
|  | 	r1, _, e1 := syscall.Syscall(procConnectNamedPipe.Addr(), 2, uintptr(pipe), uintptr(unsafe.Pointer(o)), 0) | ||||||
|  | 	if r1 == 0 { | ||||||
|  | 		if e1 != 0 { | ||||||
|  | 			err = errnoErr(e1) | ||||||
|  | 		} else { | ||||||
|  | 			err = syscall.EINVAL | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *syscall.SecurityAttributes) (handle syscall.Handle, err error) { | ||||||
|  | 	var _p0 *uint16 | ||||||
|  | 	_p0, err = syscall.UTF16PtrFromString(name) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	return _createNamedPipe(_p0, flags, pipeMode, maxInstances, outSize, inSize, defaultTimeout, sa) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func _createNamedPipe(name *uint16, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *syscall.SecurityAttributes) (handle syscall.Handle, err error) { | ||||||
|  | 	r0, _, e1 := syscall.Syscall9(procCreateNamedPipeW.Addr(), 8, uintptr(unsafe.Pointer(name)), uintptr(flags), uintptr(pipeMode), uintptr(maxInstances), uintptr(outSize), uintptr(inSize), uintptr(defaultTimeout), uintptr(unsafe.Pointer(sa)), 0) | ||||||
|  | 	handle = syscall.Handle(r0) | ||||||
|  | 	if handle == syscall.InvalidHandle { | ||||||
|  | 		if e1 != 0 { | ||||||
|  | 			err = errnoErr(e1) | ||||||
|  | 		} else { | ||||||
|  | 			err = syscall.EINVAL | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func createFile(name string, access uint32, mode uint32, sa *syscall.SecurityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) { | ||||||
|  | 	var _p0 *uint16 | ||||||
|  | 	_p0, err = syscall.UTF16PtrFromString(name) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	return _createFile(_p0, access, mode, sa, createmode, attrs, templatefile) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func _createFile(name *uint16, access uint32, mode uint32, sa *syscall.SecurityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) { | ||||||
|  | 	r0, _, e1 := syscall.Syscall9(procCreateFileW.Addr(), 7, uintptr(unsafe.Pointer(name)), uintptr(access), uintptr(mode), uintptr(unsafe.Pointer(sa)), uintptr(createmode), uintptr(attrs), uintptr(templatefile), 0, 0) | ||||||
|  | 	handle = syscall.Handle(r0) | ||||||
|  | 	if handle == syscall.InvalidHandle { | ||||||
|  | 		if e1 != 0 { | ||||||
|  | 			err = errnoErr(e1) | ||||||
|  | 		} else { | ||||||
|  | 			err = syscall.EINVAL | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func waitNamedPipe(name string, timeout uint32) (err error) { | ||||||
|  | 	var _p0 *uint16 | ||||||
|  | 	_p0, err = syscall.UTF16PtrFromString(name) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	return _waitNamedPipe(_p0, timeout) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func _waitNamedPipe(name *uint16, timeout uint32) (err error) { | ||||||
|  | 	r1, _, e1 := syscall.Syscall(procWaitNamedPipeW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(timeout), 0) | ||||||
|  | 	if r1 == 0 { | ||||||
|  | 		if e1 != 0 { | ||||||
|  | 			err = errnoErr(e1) | ||||||
|  | 		} else { | ||||||
|  | 			err = syscall.EINVAL | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func getNamedPipeInfo(pipe syscall.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) { | ||||||
|  | 	r1, _, e1 := syscall.Syscall6(procGetNamedPipeInfo.Addr(), 5, uintptr(pipe), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(outSize)), uintptr(unsafe.Pointer(inSize)), uintptr(unsafe.Pointer(maxInstances)), 0) | ||||||
|  | 	if r1 == 0 { | ||||||
|  | 		if e1 != 0 { | ||||||
|  | 			err = errnoErr(e1) | ||||||
|  | 		} else { | ||||||
|  | 			err = syscall.EINVAL | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func getNamedPipeHandleState(pipe syscall.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) { | ||||||
|  | 	r1, _, e1 := syscall.Syscall9(procGetNamedPipeHandleStateW.Addr(), 7, uintptr(pipe), uintptr(unsafe.Pointer(state)), uintptr(unsafe.Pointer(curInstances)), uintptr(unsafe.Pointer(maxCollectionCount)), uintptr(unsafe.Pointer(collectDataTimeout)), uintptr(unsafe.Pointer(userName)), uintptr(maxUserNameSize), 0, 0) | ||||||
|  | 	if r1 == 0 { | ||||||
|  | 		if e1 != 0 { | ||||||
|  | 			err = errnoErr(e1) | ||||||
|  | 		} else { | ||||||
|  | 			err = syscall.EINVAL | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func localAlloc(uFlags uint32, length uint32) (ptr uintptr) { | ||||||
|  | 	r0, _, _ := syscall.Syscall(procLocalAlloc.Addr(), 2, uintptr(uFlags), uintptr(length), 0) | ||||||
|  | 	ptr = uintptr(r0) | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func lookupAccountName(systemName *uint16, accountName string, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) { | ||||||
|  | 	var _p0 *uint16 | ||||||
|  | 	_p0, err = syscall.UTF16PtrFromString(accountName) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	return _lookupAccountName(systemName, _p0, sid, sidSize, refDomain, refDomainSize, sidNameUse) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func _lookupAccountName(systemName *uint16, accountName *uint16, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) { | ||||||
|  | 	r1, _, e1 := syscall.Syscall9(procLookupAccountNameW.Addr(), 7, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(accountName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(sidSize)), uintptr(unsafe.Pointer(refDomain)), uintptr(unsafe.Pointer(refDomainSize)), uintptr(unsafe.Pointer(sidNameUse)), 0, 0) | ||||||
|  | 	if r1 == 0 { | ||||||
|  | 		if e1 != 0 { | ||||||
|  | 			err = errnoErr(e1) | ||||||
|  | 		} else { | ||||||
|  | 			err = syscall.EINVAL | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func convertSidToStringSid(sid *byte, str **uint16) (err error) { | ||||||
|  | 	r1, _, e1 := syscall.Syscall(procConvertSidToStringSidW.Addr(), 2, uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(str)), 0) | ||||||
|  | 	if r1 == 0 { | ||||||
|  | 		if e1 != 0 { | ||||||
|  | 			err = errnoErr(e1) | ||||||
|  | 		} else { | ||||||
|  | 			err = syscall.EINVAL | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func convertStringSecurityDescriptorToSecurityDescriptor(str string, revision uint32, sd *uintptr, size *uint32) (err error) { | ||||||
|  | 	var _p0 *uint16 | ||||||
|  | 	_p0, err = syscall.UTF16PtrFromString(str) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	return _convertStringSecurityDescriptorToSecurityDescriptor(_p0, revision, sd, size) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func _convertStringSecurityDescriptorToSecurityDescriptor(str *uint16, revision uint32, sd *uintptr, size *uint32) (err error) { | ||||||
|  | 	r1, _, e1 := syscall.Syscall6(procConvertStringSecurityDescriptorToSecurityDescriptorW.Addr(), 4, uintptr(unsafe.Pointer(str)), uintptr(revision), uintptr(unsafe.Pointer(sd)), uintptr(unsafe.Pointer(size)), 0, 0) | ||||||
|  | 	if r1 == 0 { | ||||||
|  | 		if e1 != 0 { | ||||||
|  | 			err = errnoErr(e1) | ||||||
|  | 		} else { | ||||||
|  | 			err = syscall.EINVAL | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func convertSecurityDescriptorToStringSecurityDescriptor(sd *byte, revision uint32, secInfo uint32, sddl **uint16, sddlSize *uint32) (err error) { | ||||||
|  | 	r1, _, e1 := syscall.Syscall6(procConvertSecurityDescriptorToStringSecurityDescriptorW.Addr(), 5, uintptr(unsafe.Pointer(sd)), uintptr(revision), uintptr(secInfo), uintptr(unsafe.Pointer(sddl)), uintptr(unsafe.Pointer(sddlSize)), 0) | ||||||
|  | 	if r1 == 0 { | ||||||
|  | 		if e1 != 0 { | ||||||
|  | 			err = errnoErr(e1) | ||||||
|  | 		} else { | ||||||
|  | 			err = syscall.EINVAL | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func localFree(mem uintptr) { | ||||||
|  | 	syscall.Syscall(procLocalFree.Addr(), 1, uintptr(mem), 0, 0) | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func getSecurityDescriptorLength(sd uintptr) (len uint32) { | ||||||
|  | 	r0, _, _ := syscall.Syscall(procGetSecurityDescriptorLength.Addr(), 1, uintptr(sd), 0, 0) | ||||||
|  | 	len = uint32(r0) | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func getFileInformationByHandleEx(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) { | ||||||
|  | 	r1, _, e1 := syscall.Syscall6(procGetFileInformationByHandleEx.Addr(), 4, uintptr(h), uintptr(class), uintptr(unsafe.Pointer(buffer)), uintptr(size), 0, 0) | ||||||
|  | 	if r1 == 0 { | ||||||
|  | 		if e1 != 0 { | ||||||
|  | 			err = errnoErr(e1) | ||||||
|  | 		} else { | ||||||
|  | 			err = syscall.EINVAL | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func setFileInformationByHandle(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) { | ||||||
|  | 	r1, _, e1 := syscall.Syscall6(procSetFileInformationByHandle.Addr(), 4, uintptr(h), uintptr(class), uintptr(unsafe.Pointer(buffer)), uintptr(size), 0, 0) | ||||||
|  | 	if r1 == 0 { | ||||||
|  | 		if e1 != 0 { | ||||||
|  | 			err = errnoErr(e1) | ||||||
|  | 		} else { | ||||||
|  | 			err = syscall.EINVAL | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func adjustTokenPrivileges(token windows.Token, releaseAll bool, input *byte, outputSize uint32, output *byte, requiredSize *uint32) (success bool, err error) { | ||||||
|  | 	var _p0 uint32 | ||||||
|  | 	if releaseAll { | ||||||
|  | 		_p0 = 1 | ||||||
|  | 	} else { | ||||||
|  | 		_p0 = 0 | ||||||
|  | 	} | ||||||
|  | 	r0, _, e1 := syscall.Syscall6(procAdjustTokenPrivileges.Addr(), 6, uintptr(token), uintptr(_p0), uintptr(unsafe.Pointer(input)), uintptr(outputSize), uintptr(unsafe.Pointer(output)), uintptr(unsafe.Pointer(requiredSize))) | ||||||
|  | 	success = r0 != 0 | ||||||
|  | 	if true { | ||||||
|  | 		if e1 != 0 { | ||||||
|  | 			err = errnoErr(e1) | ||||||
|  | 		} else { | ||||||
|  | 			err = syscall.EINVAL | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func impersonateSelf(level uint32) (err error) { | ||||||
|  | 	r1, _, e1 := syscall.Syscall(procImpersonateSelf.Addr(), 1, uintptr(level), 0, 0) | ||||||
|  | 	if r1 == 0 { | ||||||
|  | 		if e1 != 0 { | ||||||
|  | 			err = errnoErr(e1) | ||||||
|  | 		} else { | ||||||
|  | 			err = syscall.EINVAL | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func revertToSelf() (err error) { | ||||||
|  | 	r1, _, e1 := syscall.Syscall(procRevertToSelf.Addr(), 0, 0, 0, 0) | ||||||
|  | 	if r1 == 0 { | ||||||
|  | 		if e1 != 0 { | ||||||
|  | 			err = errnoErr(e1) | ||||||
|  | 		} else { | ||||||
|  | 			err = syscall.EINVAL | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func openThreadToken(thread syscall.Handle, accessMask uint32, openAsSelf bool, token *windows.Token) (err error) { | ||||||
|  | 	var _p0 uint32 | ||||||
|  | 	if openAsSelf { | ||||||
|  | 		_p0 = 1 | ||||||
|  | 	} else { | ||||||
|  | 		_p0 = 0 | ||||||
|  | 	} | ||||||
|  | 	r1, _, e1 := syscall.Syscall6(procOpenThreadToken.Addr(), 4, uintptr(thread), uintptr(accessMask), uintptr(_p0), uintptr(unsafe.Pointer(token)), 0, 0) | ||||||
|  | 	if r1 == 0 { | ||||||
|  | 		if e1 != 0 { | ||||||
|  | 			err = errnoErr(e1) | ||||||
|  | 		} else { | ||||||
|  | 			err = syscall.EINVAL | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func getCurrentThread() (h syscall.Handle) { | ||||||
|  | 	r0, _, _ := syscall.Syscall(procGetCurrentThread.Addr(), 0, 0, 0, 0) | ||||||
|  | 	h = syscall.Handle(r0) | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func lookupPrivilegeValue(systemName string, name string, luid *uint64) (err error) { | ||||||
|  | 	var _p0 *uint16 | ||||||
|  | 	_p0, err = syscall.UTF16PtrFromString(systemName) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	var _p1 *uint16 | ||||||
|  | 	_p1, err = syscall.UTF16PtrFromString(name) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	return _lookupPrivilegeValue(_p0, _p1, luid) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func _lookupPrivilegeValue(systemName *uint16, name *uint16, luid *uint64) (err error) { | ||||||
|  | 	r1, _, e1 := syscall.Syscall(procLookupPrivilegeValueW.Addr(), 3, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(luid))) | ||||||
|  | 	if r1 == 0 { | ||||||
|  | 		if e1 != 0 { | ||||||
|  | 			err = errnoErr(e1) | ||||||
|  | 		} else { | ||||||
|  | 			err = syscall.EINVAL | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func lookupPrivilegeName(systemName string, luid *uint64, buffer *uint16, size *uint32) (err error) { | ||||||
|  | 	var _p0 *uint16 | ||||||
|  | 	_p0, err = syscall.UTF16PtrFromString(systemName) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	return _lookupPrivilegeName(_p0, luid, buffer, size) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func _lookupPrivilegeName(systemName *uint16, luid *uint64, buffer *uint16, size *uint32) (err error) { | ||||||
|  | 	r1, _, e1 := syscall.Syscall6(procLookupPrivilegeNameW.Addr(), 4, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(luid)), uintptr(unsafe.Pointer(buffer)), uintptr(unsafe.Pointer(size)), 0, 0) | ||||||
|  | 	if r1 == 0 { | ||||||
|  | 		if e1 != 0 { | ||||||
|  | 			err = errnoErr(e1) | ||||||
|  | 		} else { | ||||||
|  | 			err = syscall.EINVAL | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func lookupPrivilegeDisplayName(systemName string, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) { | ||||||
|  | 	var _p0 *uint16 | ||||||
|  | 	_p0, err = syscall.UTF16PtrFromString(systemName) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	return _lookupPrivilegeDisplayName(_p0, name, buffer, size, languageId) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func _lookupPrivilegeDisplayName(systemName *uint16, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) { | ||||||
|  | 	r1, _, e1 := syscall.Syscall6(procLookupPrivilegeDisplayNameW.Addr(), 5, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(buffer)), uintptr(unsafe.Pointer(size)), uintptr(unsafe.Pointer(languageId)), 0) | ||||||
|  | 	if r1 == 0 { | ||||||
|  | 		if e1 != 0 { | ||||||
|  | 			err = errnoErr(e1) | ||||||
|  | 		} else { | ||||||
|  | 			err = syscall.EINVAL | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func backupRead(h syscall.Handle, b []byte, bytesRead *uint32, abort bool, processSecurity bool, context *uintptr) (err error) { | ||||||
|  | 	var _p0 *byte | ||||||
|  | 	if len(b) > 0 { | ||||||
|  | 		_p0 = &b[0] | ||||||
|  | 	} | ||||||
|  | 	var _p1 uint32 | ||||||
|  | 	if abort { | ||||||
|  | 		_p1 = 1 | ||||||
|  | 	} else { | ||||||
|  | 		_p1 = 0 | ||||||
|  | 	} | ||||||
|  | 	var _p2 uint32 | ||||||
|  | 	if processSecurity { | ||||||
|  | 		_p2 = 1 | ||||||
|  | 	} else { | ||||||
|  | 		_p2 = 0 | ||||||
|  | 	} | ||||||
|  | 	r1, _, e1 := syscall.Syscall9(procBackupRead.Addr(), 7, uintptr(h), uintptr(unsafe.Pointer(_p0)), uintptr(len(b)), uintptr(unsafe.Pointer(bytesRead)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(context)), 0, 0) | ||||||
|  | 	if r1 == 0 { | ||||||
|  | 		if e1 != 0 { | ||||||
|  | 			err = errnoErr(e1) | ||||||
|  | 		} else { | ||||||
|  | 			err = syscall.EINVAL | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func backupWrite(h syscall.Handle, b []byte, bytesWritten *uint32, abort bool, processSecurity bool, context *uintptr) (err error) { | ||||||
|  | 	var _p0 *byte | ||||||
|  | 	if len(b) > 0 { | ||||||
|  | 		_p0 = &b[0] | ||||||
|  | 	} | ||||||
|  | 	var _p1 uint32 | ||||||
|  | 	if abort { | ||||||
|  | 		_p1 = 1 | ||||||
|  | 	} else { | ||||||
|  | 		_p1 = 0 | ||||||
|  | 	} | ||||||
|  | 	var _p2 uint32 | ||||||
|  | 	if processSecurity { | ||||||
|  | 		_p2 = 1 | ||||||
|  | 	} else { | ||||||
|  | 		_p2 = 0 | ||||||
|  | 	} | ||||||
|  | 	r1, _, e1 := syscall.Syscall9(procBackupWrite.Addr(), 7, uintptr(h), uintptr(unsafe.Pointer(_p0)), uintptr(len(b)), uintptr(unsafe.Pointer(bytesWritten)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(context)), 0, 0) | ||||||
|  | 	if r1 == 0 { | ||||||
|  | 		if e1 != 0 { | ||||||
|  | 			err = errnoErr(e1) | ||||||
|  | 		} else { | ||||||
|  | 			err = syscall.EINVAL | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
							
								
								
									
										21
									
								
								vendor/github.com/Microsoft/hcsshim/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								vendor/github.com/Microsoft/hcsshim/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | |||||||
|  | The MIT License (MIT) | ||||||
|  |  | ||||||
|  | Copyright (c) 2015 Microsoft | ||||||
|  |  | ||||||
|  | Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  | of this software and associated documentation files (the "Software"), to deal | ||||||
|  | in the Software without restriction, including without limitation the rights | ||||||
|  | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  | copies of the Software, and to permit persons to whom the Software is | ||||||
|  | furnished to do so, subject to the following conditions: | ||||||
|  |  | ||||||
|  | The above copyright notice and this permission notice shall be included in all | ||||||
|  | copies or substantial portions of the Software. | ||||||
|  |  | ||||||
|  | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||||
|  | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||||
|  | SOFTWARE. | ||||||
							
								
								
									
										51
									
								
								vendor/github.com/Microsoft/hcsshim/osversion/osversion.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								vendor/github.com/Microsoft/hcsshim/osversion/osversion.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,51 @@ | |||||||
|  | package osversion | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  |  | ||||||
|  | 	"golang.org/x/sys/windows" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // OSVersion is a wrapper for Windows version information | ||||||
|  | // https://msdn.microsoft.com/en-us/library/windows/desktop/ms724439(v=vs.85).aspx | ||||||
|  | type OSVersion struct { | ||||||
|  | 	Version      uint32 | ||||||
|  | 	MajorVersion uint8 | ||||||
|  | 	MinorVersion uint8 | ||||||
|  | 	Build        uint16 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // https://msdn.microsoft.com/en-us/library/windows/desktop/ms724833(v=vs.85).aspx | ||||||
|  | type osVersionInfoEx struct { | ||||||
|  | 	OSVersionInfoSize uint32 | ||||||
|  | 	MajorVersion      uint32 | ||||||
|  | 	MinorVersion      uint32 | ||||||
|  | 	BuildNumber       uint32 | ||||||
|  | 	PlatformID        uint32 | ||||||
|  | 	CSDVersion        [128]uint16 | ||||||
|  | 	ServicePackMajor  uint16 | ||||||
|  | 	ServicePackMinor  uint16 | ||||||
|  | 	SuiteMask         uint16 | ||||||
|  | 	ProductType       byte | ||||||
|  | 	Reserve           byte | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Get gets the operating system version on Windows. | ||||||
|  | // The calling application must be manifested to get the correct version information. | ||||||
|  | func Get() OSVersion { | ||||||
|  | 	var err error | ||||||
|  | 	osv := OSVersion{} | ||||||
|  | 	osv.Version, err = windows.GetVersion() | ||||||
|  | 	if err != nil { | ||||||
|  | 		// GetVersion never fails. | ||||||
|  | 		panic(err) | ||||||
|  | 	} | ||||||
|  | 	osv.MajorVersion = uint8(osv.Version & 0xFF) | ||||||
|  | 	osv.MinorVersion = uint8(osv.Version >> 8 & 0xFF) | ||||||
|  | 	osv.Build = uint16(osv.Version >> 16) | ||||||
|  | 	return osv | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (osv OSVersion) ToString() string { | ||||||
|  | 	return fmt.Sprintf("%d.%d.%d", osv.MajorVersion, osv.MinorVersion, osv.Build) | ||||||
|  | } | ||||||
							
								
								
									
										10
									
								
								vendor/github.com/Microsoft/hcsshim/osversion/windowsbuilds.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								vendor/github.com/Microsoft/hcsshim/osversion/windowsbuilds.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  | package osversion | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  |  | ||||||
|  | 	// RS2 was a client-only release in case you're asking why it's not in the list. | ||||||
|  | 	RS1 = 14393 | ||||||
|  | 	RS3 = 16299 | ||||||
|  | 	RS4 = 17134 | ||||||
|  | 	RS5 = 17763 | ||||||
|  | ) | ||||||
							
								
								
									
										22
									
								
								vendor/github.com/cenkalti/backoff/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								vendor/github.com/cenkalti/backoff/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | |||||||
|  | # Compiled Object files, Static and Dynamic libs (Shared Objects) | ||||||
|  | *.o | ||||||
|  | *.a | ||||||
|  | *.so | ||||||
|  |  | ||||||
|  | # Folders | ||||||
|  | _obj | ||||||
|  | _test | ||||||
|  |  | ||||||
|  | # Architecture specific extensions/prefixes | ||||||
|  | *.[568vq] | ||||||
|  | [568vq].out | ||||||
|  |  | ||||||
|  | *.cgo1.go | ||||||
|  | *.cgo2.c | ||||||
|  | _cgo_defun.c | ||||||
|  | _cgo_gotypes.go | ||||||
|  | _cgo_export.* | ||||||
|  |  | ||||||
|  | _testmain.go | ||||||
|  |  | ||||||
|  | *.exe | ||||||
							
								
								
									
										10
									
								
								vendor/github.com/cenkalti/backoff/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								vendor/github.com/cenkalti/backoff/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  | language: go | ||||||
|  | go: | ||||||
|  |   - 1.7 | ||||||
|  |   - 1.x | ||||||
|  |   - tip | ||||||
|  | before_install: | ||||||
|  |   - go get github.com/mattn/goveralls | ||||||
|  |   - go get golang.org/x/tools/cmd/cover | ||||||
|  | script: | ||||||
|  |   - $HOME/gopath/bin/goveralls -service=travis-ci | ||||||
							
								
								
									
										20
									
								
								vendor/github.com/cenkalti/backoff/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								vendor/github.com/cenkalti/backoff/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | |||||||
|  | The MIT License (MIT) | ||||||
|  |  | ||||||
|  | Copyright (c) 2014 Cenk Altı | ||||||
|  |  | ||||||
|  | Permission is hereby granted, free of charge, to any person obtaining a copy of | ||||||
|  | this software and associated documentation files (the "Software"), to deal in | ||||||
|  | the Software without restriction, including without limitation the rights to | ||||||
|  | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of | ||||||
|  | the Software, and to permit persons to whom the Software is furnished to do so, | ||||||
|  | subject to the following conditions: | ||||||
|  |  | ||||||
|  | The above copyright notice and this permission notice shall be included in all | ||||||
|  | copies or substantial portions of the Software. | ||||||
|  |  | ||||||
|  | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS | ||||||
|  | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR | ||||||
|  | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | ||||||
|  | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||||||
|  | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||||||
							
								
								
									
										30
									
								
								vendor/github.com/cenkalti/backoff/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								vendor/github.com/cenkalti/backoff/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | |||||||
|  | # Exponential Backoff [![GoDoc][godoc image]][godoc] [![Build Status][travis image]][travis] [![Coverage Status][coveralls image]][coveralls] | ||||||
|  |  | ||||||
|  | This is a Go port of the exponential backoff algorithm from [Google's HTTP Client Library for Java][google-http-java-client]. | ||||||
|  |  | ||||||
|  | [Exponential backoff][exponential backoff wiki] | ||||||
|  | is an algorithm that uses feedback to multiplicatively decrease the rate of some process, | ||||||
|  | in order to gradually find an acceptable rate. | ||||||
|  | The retries exponentially increase and stop increasing when a certain threshold is met. | ||||||
|  |  | ||||||
|  | ## Usage | ||||||
|  |  | ||||||
|  | See https://godoc.org/github.com/cenkalti/backoff#pkg-examples | ||||||
|  |  | ||||||
|  | ## Contributing | ||||||
|  |  | ||||||
|  | * I would like to keep this library as small as possible. | ||||||
|  | * Please don't send a PR without opening an issue and discussing it first. | ||||||
|  | * If proposed change is not a common use case, I will probably not accept it. | ||||||
|  |  | ||||||
|  | [godoc]: https://godoc.org/github.com/cenkalti/backoff | ||||||
|  | [godoc image]: https://godoc.org/github.com/cenkalti/backoff?status.png | ||||||
|  | [travis]: https://travis-ci.org/cenkalti/backoff | ||||||
|  | [travis image]: https://travis-ci.org/cenkalti/backoff.png?branch=master | ||||||
|  | [coveralls]: https://coveralls.io/github/cenkalti/backoff?branch=master | ||||||
|  | [coveralls image]: https://coveralls.io/repos/github/cenkalti/backoff/badge.svg?branch=master | ||||||
|  |  | ||||||
|  | [google-http-java-client]: https://github.com/google/google-http-java-client/blob/da1aa993e90285ec18579f1553339b00e19b3ab5/google-http-client/src/main/java/com/google/api/client/util/ExponentialBackOff.java | ||||||
|  | [exponential backoff wiki]: http://en.wikipedia.org/wiki/Exponential_backoff | ||||||
|  |  | ||||||
|  | [advanced example]: https://godoc.org/github.com/cenkalti/backoff#example_ | ||||||
							
								
								
									
										66
									
								
								vendor/github.com/cenkalti/backoff/backoff.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								vendor/github.com/cenkalti/backoff/backoff.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,66 @@ | |||||||
|  | // Package backoff implements backoff algorithms for retrying operations. | ||||||
|  | // | ||||||
|  | // Use Retry function for retrying operations that may fail. | ||||||
|  | // If Retry does not meet your needs, | ||||||
|  | // copy/paste the function into your project and modify as you wish. | ||||||
|  | // | ||||||
|  | // There is also Ticker type similar to time.Ticker. | ||||||
|  | // You can use it if you need to work with channels. | ||||||
|  | // | ||||||
|  | // See Examples section below for usage examples. | ||||||
|  | package backoff | ||||||
|  |  | ||||||
|  | import "time" | ||||||
|  |  | ||||||
|  | // BackOff is a backoff policy for retrying an operation. | ||||||
|  | type BackOff interface { | ||||||
|  | 	// NextBackOff returns the duration to wait before retrying the operation, | ||||||
|  | 	// or backoff. Stop to indicate that no more retries should be made. | ||||||
|  | 	// | ||||||
|  | 	// Example usage: | ||||||
|  | 	// | ||||||
|  | 	// 	duration := backoff.NextBackOff(); | ||||||
|  | 	// 	if (duration == backoff.Stop) { | ||||||
|  | 	// 		// Do not retry operation. | ||||||
|  | 	// 	} else { | ||||||
|  | 	// 		// Sleep for duration and retry operation. | ||||||
|  | 	// 	} | ||||||
|  | 	// | ||||||
|  | 	NextBackOff() time.Duration | ||||||
|  |  | ||||||
|  | 	// Reset to initial state. | ||||||
|  | 	Reset() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Stop indicates that no more retries should be made for use in NextBackOff(). | ||||||
|  | const Stop time.Duration = -1 | ||||||
|  |  | ||||||
|  | // ZeroBackOff is a fixed backoff policy whose backoff time is always zero, | ||||||
|  | // meaning that the operation is retried immediately without waiting, indefinitely. | ||||||
|  | type ZeroBackOff struct{} | ||||||
|  |  | ||||||
|  | func (b *ZeroBackOff) Reset() {} | ||||||
|  |  | ||||||
|  | func (b *ZeroBackOff) NextBackOff() time.Duration { return 0 } | ||||||
|  |  | ||||||
|  | // StopBackOff is a fixed backoff policy that always returns backoff.Stop for | ||||||
|  | // NextBackOff(), meaning that the operation should never be retried. | ||||||
|  | type StopBackOff struct{} | ||||||
|  |  | ||||||
|  | func (b *StopBackOff) Reset() {} | ||||||
|  |  | ||||||
|  | func (b *StopBackOff) NextBackOff() time.Duration { return Stop } | ||||||
|  |  | ||||||
|  | // ConstantBackOff is a backoff policy that always returns the same backoff delay. | ||||||
|  | // This is in contrast to an exponential backoff policy, | ||||||
|  | // which returns a delay that grows longer as you call NextBackOff() over and over again. | ||||||
|  | type ConstantBackOff struct { | ||||||
|  | 	Interval time.Duration | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (b *ConstantBackOff) Reset()                     {} | ||||||
|  | func (b *ConstantBackOff) NextBackOff() time.Duration { return b.Interval } | ||||||
|  |  | ||||||
|  | func NewConstantBackOff(d time.Duration) *ConstantBackOff { | ||||||
|  | 	return &ConstantBackOff{Interval: d} | ||||||
|  | } | ||||||
							
								
								
									
										63
									
								
								vendor/github.com/cenkalti/backoff/context.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								vendor/github.com/cenkalti/backoff/context.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,63 @@ | |||||||
|  | package backoff | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"context" | ||||||
|  | 	"time" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // BackOffContext is a backoff policy that stops retrying after the context | ||||||
|  | // is canceled. | ||||||
|  | type BackOffContext interface { | ||||||
|  | 	BackOff | ||||||
|  | 	Context() context.Context | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type backOffContext struct { | ||||||
|  | 	BackOff | ||||||
|  | 	ctx context.Context | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // WithContext returns a BackOffContext with context ctx | ||||||
|  | // | ||||||
|  | // ctx must not be nil | ||||||
|  | func WithContext(b BackOff, ctx context.Context) BackOffContext { | ||||||
|  | 	if ctx == nil { | ||||||
|  | 		panic("nil context") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if b, ok := b.(*backOffContext); ok { | ||||||
|  | 		return &backOffContext{ | ||||||
|  | 			BackOff: b.BackOff, | ||||||
|  | 			ctx:     ctx, | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return &backOffContext{ | ||||||
|  | 		BackOff: b, | ||||||
|  | 		ctx:     ctx, | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func ensureContext(b BackOff) BackOffContext { | ||||||
|  | 	if cb, ok := b.(BackOffContext); ok { | ||||||
|  | 		return cb | ||||||
|  | 	} | ||||||
|  | 	return WithContext(b, context.Background()) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (b *backOffContext) Context() context.Context { | ||||||
|  | 	return b.ctx | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (b *backOffContext) NextBackOff() time.Duration { | ||||||
|  | 	select { | ||||||
|  | 	case <-b.ctx.Done(): | ||||||
|  | 		return Stop | ||||||
|  | 	default: | ||||||
|  | 	} | ||||||
|  | 	next := b.BackOff.NextBackOff() | ||||||
|  | 	if deadline, ok := b.ctx.Deadline(); ok && deadline.Sub(time.Now()) < next { | ||||||
|  | 		return Stop | ||||||
|  | 	} | ||||||
|  | 	return next | ||||||
|  | } | ||||||
							
								
								
									
										153
									
								
								vendor/github.com/cenkalti/backoff/exponential.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										153
									
								
								vendor/github.com/cenkalti/backoff/exponential.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,153 @@ | |||||||
|  | package backoff | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"math/rand" | ||||||
|  | 	"time" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | ExponentialBackOff is a backoff implementation that increases the backoff | ||||||
|  | period for each retry attempt using a randomization function that grows exponentially. | ||||||
|  |  | ||||||
|  | NextBackOff() is calculated using the following formula: | ||||||
|  |  | ||||||
|  |  randomized interval = | ||||||
|  |      RetryInterval * (random value in range [1 - RandomizationFactor, 1 + RandomizationFactor]) | ||||||
|  |  | ||||||
|  | In other words NextBackOff() will range between the randomization factor | ||||||
|  | percentage below and above the retry interval. | ||||||
|  |  | ||||||
|  | For example, given the following parameters: | ||||||
|  |  | ||||||
|  |  RetryInterval = 2 | ||||||
|  |  RandomizationFactor = 0.5 | ||||||
|  |  Multiplier = 2 | ||||||
|  |  | ||||||
|  | the actual backoff period used in the next retry attempt will range between 1 and 3 seconds, | ||||||
|  | multiplied by the exponential, that is, between 2 and 6 seconds. | ||||||
|  |  | ||||||
|  | Note: MaxInterval caps the RetryInterval and not the randomized interval. | ||||||
|  |  | ||||||
|  | If the time elapsed since an ExponentialBackOff instance is created goes past the | ||||||
|  | MaxElapsedTime, then the method NextBackOff() starts returning backoff.Stop. | ||||||
|  |  | ||||||
|  | The elapsed time can be reset by calling Reset(). | ||||||
|  |  | ||||||
|  | Example: Given the following default arguments, for 10 tries the sequence will be, | ||||||
|  | and assuming we go over the MaxElapsedTime on the 10th try: | ||||||
|  |  | ||||||
|  |  Request #  RetryInterval (seconds)  Randomized Interval (seconds) | ||||||
|  |  | ||||||
|  |   1          0.5                     [0.25,   0.75] | ||||||
|  |   2          0.75                    [0.375,  1.125] | ||||||
|  |   3          1.125                   [0.562,  1.687] | ||||||
|  |   4          1.687                   [0.8435, 2.53] | ||||||
|  |   5          2.53                    [1.265,  3.795] | ||||||
|  |   6          3.795                   [1.897,  5.692] | ||||||
|  |   7          5.692                   [2.846,  8.538] | ||||||
|  |   8          8.538                   [4.269, 12.807] | ||||||
|  |   9         12.807                   [6.403, 19.210] | ||||||
|  |  10         19.210                   backoff.Stop | ||||||
|  |  | ||||||
|  | Note: Implementation is not thread-safe. | ||||||
|  | */ | ||||||
|  | type ExponentialBackOff struct { | ||||||
|  | 	InitialInterval     time.Duration | ||||||
|  | 	RandomizationFactor float64 | ||||||
|  | 	Multiplier          float64 | ||||||
|  | 	MaxInterval         time.Duration | ||||||
|  | 	// After MaxElapsedTime the ExponentialBackOff stops. | ||||||
|  | 	// It never stops if MaxElapsedTime == 0. | ||||||
|  | 	MaxElapsedTime time.Duration | ||||||
|  | 	Clock          Clock | ||||||
|  |  | ||||||
|  | 	currentInterval time.Duration | ||||||
|  | 	startTime       time.Time | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Clock is an interface that returns current time for BackOff. | ||||||
|  | type Clock interface { | ||||||
|  | 	Now() time.Time | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Default values for ExponentialBackOff. | ||||||
|  | const ( | ||||||
|  | 	DefaultInitialInterval     = 500 * time.Millisecond | ||||||
|  | 	DefaultRandomizationFactor = 0.5 | ||||||
|  | 	DefaultMultiplier          = 1.5 | ||||||
|  | 	DefaultMaxInterval         = 60 * time.Second | ||||||
|  | 	DefaultMaxElapsedTime      = 15 * time.Minute | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // NewExponentialBackOff creates an instance of ExponentialBackOff using default values. | ||||||
|  | func NewExponentialBackOff() *ExponentialBackOff { | ||||||
|  | 	b := &ExponentialBackOff{ | ||||||
|  | 		InitialInterval:     DefaultInitialInterval, | ||||||
|  | 		RandomizationFactor: DefaultRandomizationFactor, | ||||||
|  | 		Multiplier:          DefaultMultiplier, | ||||||
|  | 		MaxInterval:         DefaultMaxInterval, | ||||||
|  | 		MaxElapsedTime:      DefaultMaxElapsedTime, | ||||||
|  | 		Clock:               SystemClock, | ||||||
|  | 	} | ||||||
|  | 	b.Reset() | ||||||
|  | 	return b | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type systemClock struct{} | ||||||
|  |  | ||||||
|  | func (t systemClock) Now() time.Time { | ||||||
|  | 	return time.Now() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // SystemClock implements Clock interface that uses time.Now(). | ||||||
|  | var SystemClock = systemClock{} | ||||||
|  |  | ||||||
|  | // Reset the interval back to the initial retry interval and restarts the timer. | ||||||
|  | func (b *ExponentialBackOff) Reset() { | ||||||
|  | 	b.currentInterval = b.InitialInterval | ||||||
|  | 	b.startTime = b.Clock.Now() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // NextBackOff calculates the next backoff interval using the formula: | ||||||
|  | // 	Randomized interval = RetryInterval +/- (RandomizationFactor * RetryInterval) | ||||||
|  | func (b *ExponentialBackOff) NextBackOff() time.Duration { | ||||||
|  | 	// Make sure we have not gone over the maximum elapsed time. | ||||||
|  | 	if b.MaxElapsedTime != 0 && b.GetElapsedTime() > b.MaxElapsedTime { | ||||||
|  | 		return Stop | ||||||
|  | 	} | ||||||
|  | 	defer b.incrementCurrentInterval() | ||||||
|  | 	return getRandomValueFromInterval(b.RandomizationFactor, rand.Float64(), b.currentInterval) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // GetElapsedTime returns the elapsed time since an ExponentialBackOff instance | ||||||
|  | // is created and is reset when Reset() is called. | ||||||
|  | // | ||||||
|  | // The elapsed time is computed using time.Now().UnixNano(). It is | ||||||
|  | // safe to call even while the backoff policy is used by a running | ||||||
|  | // ticker. | ||||||
|  | func (b *ExponentialBackOff) GetElapsedTime() time.Duration { | ||||||
|  | 	return b.Clock.Now().Sub(b.startTime) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Increments the current interval by multiplying it with the multiplier. | ||||||
|  | func (b *ExponentialBackOff) incrementCurrentInterval() { | ||||||
|  | 	// Check for overflow, if overflow is detected set the current interval to the max interval. | ||||||
|  | 	if float64(b.currentInterval) >= float64(b.MaxInterval)/b.Multiplier { | ||||||
|  | 		b.currentInterval = b.MaxInterval | ||||||
|  | 	} else { | ||||||
|  | 		b.currentInterval = time.Duration(float64(b.currentInterval) * b.Multiplier) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Returns a random value from the following interval: | ||||||
|  | // 	[randomizationFactor * currentInterval, randomizationFactor * currentInterval]. | ||||||
|  | func getRandomValueFromInterval(randomizationFactor, random float64, currentInterval time.Duration) time.Duration { | ||||||
|  | 	var delta = randomizationFactor * float64(currentInterval) | ||||||
|  | 	var minInterval = float64(currentInterval) - delta | ||||||
|  | 	var maxInterval = float64(currentInterval) + delta | ||||||
|  |  | ||||||
|  | 	// Get a random value from the range [minInterval, maxInterval]. | ||||||
|  | 	// The formula used below has a +1 because if the minInterval is 1 and the maxInterval is 3 then | ||||||
|  | 	// we want a 33% chance for selecting either 1, 2 or 3. | ||||||
|  | 	return time.Duration(minInterval + (random * (maxInterval - minInterval + 1))) | ||||||
|  | } | ||||||
							
								
								
									
										82
									
								
								vendor/github.com/cenkalti/backoff/retry.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								vendor/github.com/cenkalti/backoff/retry.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,82 @@ | |||||||
|  | package backoff | ||||||
|  |  | ||||||
|  | import "time" | ||||||
|  |  | ||||||
|  | // An Operation is executing by Retry() or RetryNotify(). | ||||||
|  | // The operation will be retried using a backoff policy if it returns an error. | ||||||
|  | type Operation func() error | ||||||
|  |  | ||||||
|  | // Notify is a notify-on-error function. It receives an operation error and | ||||||
|  | // backoff delay if the operation failed (with an error). | ||||||
|  | // | ||||||
|  | // NOTE that if the backoff policy stated to stop retrying, | ||||||
|  | // the notify function isn't called. | ||||||
|  | type Notify func(error, time.Duration) | ||||||
|  |  | ||||||
|  | // Retry the operation o until it does not return error or BackOff stops. | ||||||
|  | // o is guaranteed to be run at least once. | ||||||
|  | // | ||||||
|  | // If o returns a *PermanentError, the operation is not retried, and the | ||||||
|  | // wrapped error is returned. | ||||||
|  | // | ||||||
|  | // Retry sleeps the goroutine for the duration returned by BackOff after a | ||||||
|  | // failed operation returns. | ||||||
|  | func Retry(o Operation, b BackOff) error { return RetryNotify(o, b, nil) } | ||||||
|  |  | ||||||
|  | // RetryNotify calls notify function with the error and wait duration | ||||||
|  | // for each failed attempt before sleep. | ||||||
|  | func RetryNotify(operation Operation, b BackOff, notify Notify) error { | ||||||
|  | 	var err error | ||||||
|  | 	var next time.Duration | ||||||
|  | 	var t *time.Timer | ||||||
|  |  | ||||||
|  | 	cb := ensureContext(b) | ||||||
|  |  | ||||||
|  | 	b.Reset() | ||||||
|  | 	for { | ||||||
|  | 		if err = operation(); err == nil { | ||||||
|  | 			return nil | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if permanent, ok := err.(*PermanentError); ok { | ||||||
|  | 			return permanent.Err | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if next = cb.NextBackOff(); next == Stop { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if notify != nil { | ||||||
|  | 			notify(err, next) | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if t == nil { | ||||||
|  | 			t = time.NewTimer(next) | ||||||
|  | 			defer t.Stop() | ||||||
|  | 		} else { | ||||||
|  | 			t.Reset(next) | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		select { | ||||||
|  | 		case <-cb.Context().Done(): | ||||||
|  | 			return err | ||||||
|  | 		case <-t.C: | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // PermanentError signals that the operation should not be retried. | ||||||
|  | type PermanentError struct { | ||||||
|  | 	Err error | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (e *PermanentError) Error() string { | ||||||
|  | 	return e.Err.Error() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Permanent wraps the given err in a *PermanentError. | ||||||
|  | func Permanent(err error) *PermanentError { | ||||||
|  | 	return &PermanentError{ | ||||||
|  | 		Err: err, | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										82
									
								
								vendor/github.com/cenkalti/backoff/ticker.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								vendor/github.com/cenkalti/backoff/ticker.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,82 @@ | |||||||
|  | package backoff | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"sync" | ||||||
|  | 	"time" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // Ticker holds a channel that delivers `ticks' of a clock at times reported by a BackOff. | ||||||
|  | // | ||||||
|  | // Ticks will continue to arrive when the previous operation is still running, | ||||||
|  | // so operations that take a while to fail could run in quick succession. | ||||||
|  | type Ticker struct { | ||||||
|  | 	C        <-chan time.Time | ||||||
|  | 	c        chan time.Time | ||||||
|  | 	b        BackOffContext | ||||||
|  | 	stop     chan struct{} | ||||||
|  | 	stopOnce sync.Once | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // NewTicker returns a new Ticker containing a channel that will send | ||||||
|  | // the time at times specified by the BackOff argument. Ticker is | ||||||
|  | // guaranteed to tick at least once.  The channel is closed when Stop | ||||||
|  | // method is called or BackOff stops. It is not safe to manipulate the | ||||||
|  | // provided backoff policy (notably calling NextBackOff or Reset) | ||||||
|  | // while the ticker is running. | ||||||
|  | func NewTicker(b BackOff) *Ticker { | ||||||
|  | 	c := make(chan time.Time) | ||||||
|  | 	t := &Ticker{ | ||||||
|  | 		C:    c, | ||||||
|  | 		c:    c, | ||||||
|  | 		b:    ensureContext(b), | ||||||
|  | 		stop: make(chan struct{}), | ||||||
|  | 	} | ||||||
|  | 	t.b.Reset() | ||||||
|  | 	go t.run() | ||||||
|  | 	return t | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Stop turns off a ticker. After Stop, no more ticks will be sent. | ||||||
|  | func (t *Ticker) Stop() { | ||||||
|  | 	t.stopOnce.Do(func() { close(t.stop) }) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t *Ticker) run() { | ||||||
|  | 	c := t.c | ||||||
|  | 	defer close(c) | ||||||
|  |  | ||||||
|  | 	// Ticker is guaranteed to tick at least once. | ||||||
|  | 	afterC := t.send(time.Now()) | ||||||
|  |  | ||||||
|  | 	for { | ||||||
|  | 		if afterC == nil { | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		select { | ||||||
|  | 		case tick := <-afterC: | ||||||
|  | 			afterC = t.send(tick) | ||||||
|  | 		case <-t.stop: | ||||||
|  | 			t.c = nil // Prevent future ticks from being sent to the channel. | ||||||
|  | 			return | ||||||
|  | 		case <-t.b.Context().Done(): | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t *Ticker) send(tick time.Time) <-chan time.Time { | ||||||
|  | 	select { | ||||||
|  | 	case t.c <- tick: | ||||||
|  | 	case <-t.stop: | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	next := t.b.NextBackOff() | ||||||
|  | 	if next == Stop { | ||||||
|  | 		t.Stop() | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return time.After(next) | ||||||
|  | } | ||||||
							
								
								
									
										35
									
								
								vendor/github.com/cenkalti/backoff/tries.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								vendor/github.com/cenkalti/backoff/tries.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | |||||||
|  | package backoff | ||||||
|  |  | ||||||
|  | import "time" | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | WithMaxRetries creates a wrapper around another BackOff, which will | ||||||
|  | return Stop if NextBackOff() has been called too many times since | ||||||
|  | the last time Reset() was called | ||||||
|  |  | ||||||
|  | Note: Implementation is not thread-safe. | ||||||
|  | */ | ||||||
|  | func WithMaxRetries(b BackOff, max uint64) BackOff { | ||||||
|  | 	return &backOffTries{delegate: b, maxTries: max} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type backOffTries struct { | ||||||
|  | 	delegate BackOff | ||||||
|  | 	maxTries uint64 | ||||||
|  | 	numTries uint64 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (b *backOffTries) NextBackOff() time.Duration { | ||||||
|  | 	if b.maxTries > 0 { | ||||||
|  | 		if b.maxTries <= b.numTries { | ||||||
|  | 			return Stop | ||||||
|  | 		} | ||||||
|  | 		b.numTries++ | ||||||
|  | 	} | ||||||
|  | 	return b.delegate.NextBackOff() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (b *backOffTries) Reset() { | ||||||
|  | 	b.numTries = 0 | ||||||
|  | 	b.delegate.Reset() | ||||||
|  | } | ||||||
							
								
								
									
										16
									
								
								vendor/github.com/containerd/continuity/AUTHORS
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								vendor/github.com/containerd/continuity/AUTHORS
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | |||||||
|  | Aaron Lehmann <aaron.lehmann@docker.com> | ||||||
|  | Akash Gupta <akagup@microsoft.com> | ||||||
|  | Akihiro Suda <suda.akihiro@lab.ntt.co.jp> | ||||||
|  | Andrew Pennebaker <apennebaker@datapipe.com> | ||||||
|  | Brandon Philips <brandon.philips@coreos.com> | ||||||
|  | Christopher Jones <tophj@linux.vnet.ibm.com> | ||||||
|  | Daniel, Dao Quang Minh <dqminh89@gmail.com> | ||||||
|  | Derek McGowan <derek@mcgstyle.net> | ||||||
|  | Edward Pilatowicz <edward.pilatowicz@oracle.com> | ||||||
|  | Ian Campbell <ijc@docker.com> | ||||||
|  | Justin Cormack <justin.cormack@docker.com> | ||||||
|  | Justin Cummins <sul3n3t@gmail.com> | ||||||
|  | Phil Estes <estesp@gmail.com> | ||||||
|  | Stephen J Day <stephen.day@docker.com> | ||||||
|  | Tobias Klauser <tklauser@distanz.ch> | ||||||
|  | Tonis Tiigi <tonistiigi@gmail.com> | ||||||
							
								
								
									
										191
									
								
								vendor/github.com/containerd/continuity/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										191
									
								
								vendor/github.com/containerd/continuity/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,191 @@ | |||||||
|  |  | ||||||
|  |                                  Apache License | ||||||
|  |                            Version 2.0, January 2004 | ||||||
|  |                         https://www.apache.org/licenses/ | ||||||
|  |  | ||||||
|  |    TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION | ||||||
|  |  | ||||||
|  |    1. Definitions. | ||||||
|  |  | ||||||
|  |       "License" shall mean the terms and conditions for use, reproduction, | ||||||
|  |       and distribution as defined by Sections 1 through 9 of this document. | ||||||
|  |  | ||||||
|  |       "Licensor" shall mean the copyright owner or entity authorized by | ||||||
|  |       the copyright owner that is granting the License. | ||||||
|  |  | ||||||
|  |       "Legal Entity" shall mean the union of the acting entity and all | ||||||
|  |       other entities that control, are controlled by, or are under common | ||||||
|  |       control with that entity. For the purposes of this definition, | ||||||
|  |       "control" means (i) the power, direct or indirect, to cause the | ||||||
|  |       direction or management of such entity, whether by contract or | ||||||
|  |       otherwise, or (ii) ownership of fifty percent (50%) or more of the | ||||||
|  |       outstanding shares, or (iii) beneficial ownership of such entity. | ||||||
|  |  | ||||||
|  |       "You" (or "Your") shall mean an individual or Legal Entity | ||||||
|  |       exercising permissions granted by this License. | ||||||
|  |  | ||||||
|  |       "Source" form shall mean the preferred form for making modifications, | ||||||
|  |       including but not limited to software source code, documentation | ||||||
|  |       source, and configuration files. | ||||||
|  |  | ||||||
|  |       "Object" form shall mean any form resulting from mechanical | ||||||
|  |       transformation or translation of a Source form, including but | ||||||
|  |       not limited to compiled object code, generated documentation, | ||||||
|  |       and conversions to other media types. | ||||||
|  |  | ||||||
|  |       "Work" shall mean the work of authorship, whether in Source or | ||||||
|  |       Object form, made available under the License, as indicated by a | ||||||
|  |       copyright notice that is included in or attached to the work | ||||||
|  |       (an example is provided in the Appendix below). | ||||||
|  |  | ||||||
|  |       "Derivative Works" shall mean any work, whether in Source or Object | ||||||
|  |       form, that is based on (or derived from) the Work and for which the | ||||||
|  |       editorial revisions, annotations, elaborations, or other modifications | ||||||
|  |       represent, as a whole, an original work of authorship. For the purposes | ||||||
|  |       of this License, Derivative Works shall not include works that remain | ||||||
|  |       separable from, or merely link (or bind by name) to the interfaces of, | ||||||
|  |       the Work and Derivative Works thereof. | ||||||
|  |  | ||||||
|  |       "Contribution" shall mean any work of authorship, including | ||||||
|  |       the original version of the Work and any modifications or additions | ||||||
|  |       to that Work or Derivative Works thereof, that is intentionally | ||||||
|  |       submitted to Licensor for inclusion in the Work by the copyright owner | ||||||
|  |       or by an individual or Legal Entity authorized to submit on behalf of | ||||||
|  |       the copyright owner. For the purposes of this definition, "submitted" | ||||||
|  |       means any form of electronic, verbal, or written communication sent | ||||||
|  |       to the Licensor or its representatives, including but not limited to | ||||||
|  |       communication on electronic mailing lists, source code control systems, | ||||||
|  |       and issue tracking systems that are managed by, or on behalf of, the | ||||||
|  |       Licensor for the purpose of discussing and improving the Work, but | ||||||
|  |       excluding communication that is conspicuously marked or otherwise | ||||||
|  |       designated in writing by the copyright owner as "Not a Contribution." | ||||||
|  |  | ||||||
|  |       "Contributor" shall mean Licensor and any individual or Legal Entity | ||||||
|  |       on behalf of whom a Contribution has been received by Licensor and | ||||||
|  |       subsequently incorporated within the Work. | ||||||
|  |  | ||||||
|  |    2. Grant of Copyright License. Subject to the terms and conditions of | ||||||
|  |       this License, each Contributor hereby grants to You a perpetual, | ||||||
|  |       worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||||||
|  |       copyright license to reproduce, prepare Derivative Works of, | ||||||
|  |       publicly display, publicly perform, sublicense, and distribute the | ||||||
|  |       Work and such Derivative Works in Source or Object form. | ||||||
|  |  | ||||||
|  |    3. Grant of Patent License. Subject to the terms and conditions of | ||||||
|  |       this License, each Contributor hereby grants to You a perpetual, | ||||||
|  |       worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||||||
|  |       (except as stated in this section) patent license to make, have made, | ||||||
|  |       use, offer to sell, sell, import, and otherwise transfer the Work, | ||||||
|  |       where such license applies only to those patent claims licensable | ||||||
|  |       by such Contributor that are necessarily infringed by their | ||||||
|  |       Contribution(s) alone or by combination of their Contribution(s) | ||||||
|  |       with the Work to which such Contribution(s) was submitted. If You | ||||||
|  |       institute patent litigation against any entity (including a | ||||||
|  |       cross-claim or counterclaim in a lawsuit) alleging that the Work | ||||||
|  |       or a Contribution incorporated within the Work constitutes direct | ||||||
|  |       or contributory patent infringement, then any patent licenses | ||||||
|  |       granted to You under this License for that Work shall terminate | ||||||
|  |       as of the date such litigation is filed. | ||||||
|  |  | ||||||
|  |    4. Redistribution. You may reproduce and distribute copies of the | ||||||
|  |       Work or Derivative Works thereof in any medium, with or without | ||||||
|  |       modifications, and in Source or Object form, provided that You | ||||||
|  |       meet the following conditions: | ||||||
|  |  | ||||||
|  |       (a) You must give any other recipients of the Work or | ||||||
|  |           Derivative Works a copy of this License; and | ||||||
|  |  | ||||||
|  |       (b) You must cause any modified files to carry prominent notices | ||||||
|  |           stating that You changed the files; and | ||||||
|  |  | ||||||
|  |       (c) You must retain, in the Source form of any Derivative Works | ||||||
|  |           that You distribute, all copyright, patent, trademark, and | ||||||
|  |           attribution notices from the Source form of the Work, | ||||||
|  |           excluding those notices that do not pertain to any part of | ||||||
|  |           the Derivative Works; and | ||||||
|  |  | ||||||
|  |       (d) If the Work includes a "NOTICE" text file as part of its | ||||||
|  |           distribution, then any Derivative Works that You distribute must | ||||||
|  |           include a readable copy of the attribution notices contained | ||||||
|  |           within such NOTICE file, excluding those notices that do not | ||||||
|  |           pertain to any part of the Derivative Works, in at least one | ||||||
|  |           of the following places: within a NOTICE text file distributed | ||||||
|  |           as part of the Derivative Works; within the Source form or | ||||||
|  |           documentation, if provided along with the Derivative Works; or, | ||||||
|  |           within a display generated by the Derivative Works, if and | ||||||
|  |           wherever such third-party notices normally appear. The contents | ||||||
|  |           of the NOTICE file are for informational purposes only and | ||||||
|  |           do not modify the License. You may add Your own attribution | ||||||
|  |           notices within Derivative Works that You distribute, alongside | ||||||
|  |           or as an addendum to the NOTICE text from the Work, provided | ||||||
|  |           that such additional attribution notices cannot be construed | ||||||
|  |           as modifying the License. | ||||||
|  |  | ||||||
|  |       You may add Your own copyright statement to Your modifications and | ||||||
|  |       may provide additional or different license terms and conditions | ||||||
|  |       for use, reproduction, or distribution of Your modifications, or | ||||||
|  |       for any such Derivative Works as a whole, provided Your use, | ||||||
|  |       reproduction, and distribution of the Work otherwise complies with | ||||||
|  |       the conditions stated in this License. | ||||||
|  |  | ||||||
|  |    5. Submission of Contributions. Unless You explicitly state otherwise, | ||||||
|  |       any Contribution intentionally submitted for inclusion in the Work | ||||||
|  |       by You to the Licensor shall be under the terms and conditions of | ||||||
|  |       this License, without any additional terms or conditions. | ||||||
|  |       Notwithstanding the above, nothing herein shall supersede or modify | ||||||
|  |       the terms of any separate license agreement you may have executed | ||||||
|  |       with Licensor regarding such Contributions. | ||||||
|  |  | ||||||
|  |    6. Trademarks. This License does not grant permission to use the trade | ||||||
|  |       names, trademarks, service marks, or product names of the Licensor, | ||||||
|  |       except as required for reasonable and customary use in describing the | ||||||
|  |       origin of the Work and reproducing the content of the NOTICE file. | ||||||
|  |  | ||||||
|  |    7. Disclaimer of Warranty. Unless required by applicable law or | ||||||
|  |       agreed to in writing, Licensor provides the Work (and each | ||||||
|  |       Contributor provides its Contributions) on an "AS IS" BASIS, | ||||||
|  |       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | ||||||
|  |       implied, including, without limitation, any warranties or conditions | ||||||
|  |       of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A | ||||||
|  |       PARTICULAR PURPOSE. You are solely responsible for determining the | ||||||
|  |       appropriateness of using or redistributing the Work and assume any | ||||||
|  |       risks associated with Your exercise of permissions under this License. | ||||||
|  |  | ||||||
|  |    8. Limitation of Liability. In no event and under no legal theory, | ||||||
|  |       whether in tort (including negligence), contract, or otherwise, | ||||||
|  |       unless required by applicable law (such as deliberate and grossly | ||||||
|  |       negligent acts) or agreed to in writing, shall any Contributor be | ||||||
|  |       liable to You for damages, including any direct, indirect, special, | ||||||
|  |       incidental, or consequential damages of any character arising as a | ||||||
|  |       result of this License or out of the use or inability to use the | ||||||
|  |       Work (including but not limited to damages for loss of goodwill, | ||||||
|  |       work stoppage, computer failure or malfunction, or any and all | ||||||
|  |       other commercial damages or losses), even if such Contributor | ||||||
|  |       has been advised of the possibility of such damages. | ||||||
|  |  | ||||||
|  |    9. Accepting Warranty or Additional Liability. While redistributing | ||||||
|  |       the Work or Derivative Works thereof, You may choose to offer, | ||||||
|  |       and charge a fee for, acceptance of support, warranty, indemnity, | ||||||
|  |       or other liability obligations and/or rights consistent with this | ||||||
|  |       License. However, in accepting such obligations, You may act only | ||||||
|  |       on Your own behalf and on Your sole responsibility, not on behalf | ||||||
|  |       of any other Contributor, and only if You agree to indemnify, | ||||||
|  |       defend, and hold each Contributor harmless for any liability | ||||||
|  |       incurred by, or claims asserted against, such Contributor by reason | ||||||
|  |       of your accepting any such warranty or additional liability. | ||||||
|  |  | ||||||
|  |    END OF TERMS AND CONDITIONS | ||||||
|  |  | ||||||
|  |    Copyright The containerd Authors | ||||||
|  |  | ||||||
|  |    Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |    you may not use this file except in compliance with the License. | ||||||
|  |    You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |        https://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |    Unless required by applicable law or agreed to in writing, software | ||||||
|  |    distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |    See the License for the specific language governing permissions and | ||||||
|  |    limitations under the License. | ||||||
							
								
								
									
										172
									
								
								vendor/github.com/containerd/continuity/fs/copy.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										172
									
								
								vendor/github.com/containerd/continuity/fs/copy.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,172 @@ | |||||||
|  | /* | ||||||
|  |    Copyright The containerd Authors. | ||||||
|  |  | ||||||
|  |    Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |    you may not use this file except in compliance with the License. | ||||||
|  |    You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |        http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |    Unless required by applicable law or agreed to in writing, software | ||||||
|  |    distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |    See the License for the specific language governing permissions and | ||||||
|  |    limitations under the License. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | package fs | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"io/ioutil" | ||||||
|  | 	"os" | ||||||
|  | 	"path/filepath" | ||||||
|  | 	"sync" | ||||||
|  |  | ||||||
|  | 	"github.com/pkg/errors" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | var bufferPool = &sync.Pool{ | ||||||
|  | 	New: func() interface{} { | ||||||
|  | 		buffer := make([]byte, 32*1024) | ||||||
|  | 		return &buffer | ||||||
|  | 	}, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // XAttrErrorHandlers transform a non-nil xattr error. | ||||||
|  | // Return nil to ignore an error. | ||||||
|  | // xattrKey can be empty for listxattr operation. | ||||||
|  | type XAttrErrorHandler func(dst, src, xattrKey string, err error) error | ||||||
|  |  | ||||||
|  | type copyDirOpts struct { | ||||||
|  | 	xeh XAttrErrorHandler | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type CopyDirOpt func(*copyDirOpts) error | ||||||
|  |  | ||||||
|  | // WithXAttrErrorHandler allows specifying XAttrErrorHandler | ||||||
|  | // If nil XAttrErrorHandler is specified (default), CopyDir stops | ||||||
|  | // on a non-nil xattr error. | ||||||
|  | func WithXAttrErrorHandler(xeh XAttrErrorHandler) CopyDirOpt { | ||||||
|  | 	return func(o *copyDirOpts) error { | ||||||
|  | 		o.xeh = xeh | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // WithAllowXAttrErrors allows ignoring xattr errors. | ||||||
|  | func WithAllowXAttrErrors() CopyDirOpt { | ||||||
|  | 	xeh := func(dst, src, xattrKey string, err error) error { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 	return WithXAttrErrorHandler(xeh) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // CopyDir copies the directory from src to dst. | ||||||
|  | // Most efficient copy of files is attempted. | ||||||
|  | func CopyDir(dst, src string, opts ...CopyDirOpt) error { | ||||||
|  | 	var o copyDirOpts | ||||||
|  | 	for _, opt := range opts { | ||||||
|  | 		if err := opt(&o); err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	inodes := map[uint64]string{} | ||||||
|  | 	return copyDirectory(dst, src, inodes, &o) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func copyDirectory(dst, src string, inodes map[uint64]string, o *copyDirOpts) error { | ||||||
|  | 	stat, err := os.Stat(src) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return errors.Wrapf(err, "failed to stat %s", src) | ||||||
|  | 	} | ||||||
|  | 	if !stat.IsDir() { | ||||||
|  | 		return errors.Errorf("source is not directory") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if st, err := os.Stat(dst); err != nil { | ||||||
|  | 		if err := os.Mkdir(dst, stat.Mode()); err != nil { | ||||||
|  | 			return errors.Wrapf(err, "failed to mkdir %s", dst) | ||||||
|  | 		} | ||||||
|  | 	} else if !st.IsDir() { | ||||||
|  | 		return errors.Errorf("cannot copy to non-directory: %s", dst) | ||||||
|  | 	} else { | ||||||
|  | 		if err := os.Chmod(dst, stat.Mode()); err != nil { | ||||||
|  | 			return errors.Wrapf(err, "failed to chmod on %s", dst) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	fis, err := ioutil.ReadDir(src) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return errors.Wrapf(err, "failed to read %s", src) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if err := copyFileInfo(stat, dst); err != nil { | ||||||
|  | 		return errors.Wrapf(err, "failed to copy file info for %s", dst) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	for _, fi := range fis { | ||||||
|  | 		source := filepath.Join(src, fi.Name()) | ||||||
|  | 		target := filepath.Join(dst, fi.Name()) | ||||||
|  |  | ||||||
|  | 		switch { | ||||||
|  | 		case fi.IsDir(): | ||||||
|  | 			if err := copyDirectory(target, source, inodes, o); err != nil { | ||||||
|  | 				return err | ||||||
|  | 			} | ||||||
|  | 			continue | ||||||
|  | 		case (fi.Mode() & os.ModeType) == 0: | ||||||
|  | 			link, err := getLinkSource(target, fi, inodes) | ||||||
|  | 			if err != nil { | ||||||
|  | 				return errors.Wrap(err, "failed to get hardlink") | ||||||
|  | 			} | ||||||
|  | 			if link != "" { | ||||||
|  | 				if err := os.Link(link, target); err != nil { | ||||||
|  | 					return errors.Wrap(err, "failed to create hard link") | ||||||
|  | 				} | ||||||
|  | 			} else if err := CopyFile(target, source); err != nil { | ||||||
|  | 				return errors.Wrap(err, "failed to copy files") | ||||||
|  | 			} | ||||||
|  | 		case (fi.Mode() & os.ModeSymlink) == os.ModeSymlink: | ||||||
|  | 			link, err := os.Readlink(source) | ||||||
|  | 			if err != nil { | ||||||
|  | 				return errors.Wrapf(err, "failed to read link: %s", source) | ||||||
|  | 			} | ||||||
|  | 			if err := os.Symlink(link, target); err != nil { | ||||||
|  | 				return errors.Wrapf(err, "failed to create symlink: %s", target) | ||||||
|  | 			} | ||||||
|  | 		case (fi.Mode() & os.ModeDevice) == os.ModeDevice: | ||||||
|  | 			if err := copyDevice(target, fi); err != nil { | ||||||
|  | 				return errors.Wrapf(err, "failed to create device") | ||||||
|  | 			} | ||||||
|  | 		default: | ||||||
|  | 			// TODO: Support pipes and sockets | ||||||
|  | 			return errors.Wrapf(err, "unsupported mode %s", fi.Mode()) | ||||||
|  | 		} | ||||||
|  | 		if err := copyFileInfo(fi, target); err != nil { | ||||||
|  | 			return errors.Wrap(err, "failed to copy file info") | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if err := copyXAttrs(target, source, o.xeh); err != nil { | ||||||
|  | 			return errors.Wrap(err, "failed to copy xattrs") | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // CopyFile copies the source file to the target. | ||||||
|  | // The most efficient means of copying is used for the platform. | ||||||
|  | func CopyFile(target, source string) error { | ||||||
|  | 	src, err := os.Open(source) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return errors.Wrapf(err, "failed to open source %s", source) | ||||||
|  | 	} | ||||||
|  | 	defer src.Close() | ||||||
|  | 	tgt, err := os.Create(target) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return errors.Wrapf(err, "failed to open target %s", target) | ||||||
|  | 	} | ||||||
|  | 	defer tgt.Close() | ||||||
|  |  | ||||||
|  | 	return copyFileContent(tgt, src) | ||||||
|  | } | ||||||
							
								
								
									
										144
									
								
								vendor/github.com/containerd/continuity/fs/copy_linux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										144
									
								
								vendor/github.com/containerd/continuity/fs/copy_linux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,144 @@ | |||||||
|  | /* | ||||||
|  |    Copyright The containerd Authors. | ||||||
|  |  | ||||||
|  |    Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |    you may not use this file except in compliance with the License. | ||||||
|  |    You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |        http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |    Unless required by applicable law or agreed to in writing, software | ||||||
|  |    distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |    See the License for the specific language governing permissions and | ||||||
|  |    limitations under the License. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | package fs | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"io" | ||||||
|  | 	"os" | ||||||
|  | 	"syscall" | ||||||
|  |  | ||||||
|  | 	"github.com/containerd/continuity/sysx" | ||||||
|  | 	"github.com/pkg/errors" | ||||||
|  | 	"golang.org/x/sys/unix" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func copyFileInfo(fi os.FileInfo, name string) error { | ||||||
|  | 	st := fi.Sys().(*syscall.Stat_t) | ||||||
|  | 	if err := os.Lchown(name, int(st.Uid), int(st.Gid)); err != nil { | ||||||
|  | 		if os.IsPermission(err) { | ||||||
|  | 			// Normally if uid/gid are the same this would be a no-op, but some | ||||||
|  | 			// filesystems may still return EPERM... for instance NFS does this. | ||||||
|  | 			// In such a case, this is not an error. | ||||||
|  | 			if dstStat, err2 := os.Lstat(name); err2 == nil { | ||||||
|  | 				st2 := dstStat.Sys().(*syscall.Stat_t) | ||||||
|  | 				if st.Uid == st2.Uid && st.Gid == st2.Gid { | ||||||
|  | 					err = nil | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		if err != nil { | ||||||
|  | 			return errors.Wrapf(err, "failed to chown %s", name) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (fi.Mode() & os.ModeSymlink) != os.ModeSymlink { | ||||||
|  | 		if err := os.Chmod(name, fi.Mode()); err != nil { | ||||||
|  | 			return errors.Wrapf(err, "failed to chmod %s", name) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	timespec := []unix.Timespec{unix.Timespec(StatAtime(st)), unix.Timespec(StatMtime(st))} | ||||||
|  | 	if err := unix.UtimesNanoAt(unix.AT_FDCWD, name, timespec, unix.AT_SYMLINK_NOFOLLOW); err != nil { | ||||||
|  | 		return errors.Wrapf(err, "failed to utime %s", name) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const maxSSizeT = int64(^uint(0) >> 1) | ||||||
|  |  | ||||||
|  | func copyFileContent(dst, src *os.File) error { | ||||||
|  | 	st, err := src.Stat() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return errors.Wrap(err, "unable to stat source") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	size := st.Size() | ||||||
|  | 	first := true | ||||||
|  | 	srcFd := int(src.Fd()) | ||||||
|  | 	dstFd := int(dst.Fd()) | ||||||
|  |  | ||||||
|  | 	for size > 0 { | ||||||
|  | 		// Ensure that we are never trying to copy more than SSIZE_MAX at a | ||||||
|  | 		// time and at the same time avoids overflows when the file is larger | ||||||
|  | 		// than 4GB on 32-bit systems. | ||||||
|  | 		var copySize int | ||||||
|  | 		if size > maxSSizeT { | ||||||
|  | 			copySize = int(maxSSizeT) | ||||||
|  | 		} else { | ||||||
|  | 			copySize = int(size) | ||||||
|  | 		} | ||||||
|  | 		n, err := unix.CopyFileRange(srcFd, nil, dstFd, nil, copySize, 0) | ||||||
|  | 		if err != nil { | ||||||
|  | 			if (err != unix.ENOSYS && err != unix.EXDEV) || !first { | ||||||
|  | 				return errors.Wrap(err, "copy file range failed") | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			buf := bufferPool.Get().(*[]byte) | ||||||
|  | 			_, err = io.CopyBuffer(dst, src, *buf) | ||||||
|  | 			bufferPool.Put(buf) | ||||||
|  | 			return errors.Wrap(err, "userspace copy failed") | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		first = false | ||||||
|  | 		size -= int64(n) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func copyXAttrs(dst, src string, xeh XAttrErrorHandler) error { | ||||||
|  | 	xattrKeys, err := sysx.LListxattr(src) | ||||||
|  | 	if err != nil { | ||||||
|  | 		e := errors.Wrapf(err, "failed to list xattrs on %s", src) | ||||||
|  | 		if xeh != nil { | ||||||
|  | 			e = xeh(dst, src, "", e) | ||||||
|  | 		} | ||||||
|  | 		return e | ||||||
|  | 	} | ||||||
|  | 	for _, xattr := range xattrKeys { | ||||||
|  | 		data, err := sysx.LGetxattr(src, xattr) | ||||||
|  | 		if err != nil { | ||||||
|  | 			e := errors.Wrapf(err, "failed to get xattr %q on %s", xattr, src) | ||||||
|  | 			if xeh != nil { | ||||||
|  | 				if e = xeh(dst, src, xattr, e); e == nil { | ||||||
|  | 					continue | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			return e | ||||||
|  | 		} | ||||||
|  | 		if err := sysx.LSetxattr(dst, xattr, data, 0); err != nil { | ||||||
|  | 			e := errors.Wrapf(err, "failed to set xattr %q on %s", xattr, dst) | ||||||
|  | 			if xeh != nil { | ||||||
|  | 				if e = xeh(dst, src, xattr, e); e == nil { | ||||||
|  | 					continue | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			return e | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func copyDevice(dst string, fi os.FileInfo) error { | ||||||
|  | 	st, ok := fi.Sys().(*syscall.Stat_t) | ||||||
|  | 	if !ok { | ||||||
|  | 		return errors.New("unsupported stat type") | ||||||
|  | 	} | ||||||
|  | 	return unix.Mknod(dst, uint32(fi.Mode()), int(st.Rdev)) | ||||||
|  | } | ||||||
							
								
								
									
										112
									
								
								vendor/github.com/containerd/continuity/fs/copy_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								vendor/github.com/containerd/continuity/fs/copy_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,112 @@ | |||||||
|  | // +build solaris darwin freebsd | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |    Copyright The containerd Authors. | ||||||
|  |  | ||||||
|  |    Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |    you may not use this file except in compliance with the License. | ||||||
|  |    You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |        http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |    Unless required by applicable law or agreed to in writing, software | ||||||
|  |    distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |    See the License for the specific language governing permissions and | ||||||
|  |    limitations under the License. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | package fs | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"io" | ||||||
|  | 	"os" | ||||||
|  | 	"syscall" | ||||||
|  |  | ||||||
|  | 	"github.com/containerd/continuity/sysx" | ||||||
|  | 	"github.com/pkg/errors" | ||||||
|  | 	"golang.org/x/sys/unix" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func copyFileInfo(fi os.FileInfo, name string) error { | ||||||
|  | 	st := fi.Sys().(*syscall.Stat_t) | ||||||
|  | 	if err := os.Lchown(name, int(st.Uid), int(st.Gid)); err != nil { | ||||||
|  | 		if os.IsPermission(err) { | ||||||
|  | 			// Normally if uid/gid are the same this would be a no-op, but some | ||||||
|  | 			// filesystems may still return EPERM... for instance NFS does this. | ||||||
|  | 			// In such a case, this is not an error. | ||||||
|  | 			if dstStat, err2 := os.Lstat(name); err2 == nil { | ||||||
|  | 				st2 := dstStat.Sys().(*syscall.Stat_t) | ||||||
|  | 				if st.Uid == st2.Uid && st.Gid == st2.Gid { | ||||||
|  | 					err = nil | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		if err != nil { | ||||||
|  | 			return errors.Wrapf(err, "failed to chown %s", name) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (fi.Mode() & os.ModeSymlink) != os.ModeSymlink { | ||||||
|  | 		if err := os.Chmod(name, fi.Mode()); err != nil { | ||||||
|  | 			return errors.Wrapf(err, "failed to chmod %s", name) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	timespec := []syscall.Timespec{StatAtime(st), StatMtime(st)} | ||||||
|  | 	if err := syscall.UtimesNano(name, timespec); err != nil { | ||||||
|  | 		return errors.Wrapf(err, "failed to utime %s", name) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func copyFileContent(dst, src *os.File) error { | ||||||
|  | 	buf := bufferPool.Get().(*[]byte) | ||||||
|  | 	_, err := io.CopyBuffer(dst, src, *buf) | ||||||
|  | 	bufferPool.Put(buf) | ||||||
|  |  | ||||||
|  | 	return err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func copyXAttrs(dst, src string, xeh XAttrErrorHandler) error { | ||||||
|  | 	xattrKeys, err := sysx.LListxattr(src) | ||||||
|  | 	if err != nil { | ||||||
|  | 		e := errors.Wrapf(err, "failed to list xattrs on %s", src) | ||||||
|  | 		if xeh != nil { | ||||||
|  | 			e = xeh(dst, src, "", e) | ||||||
|  | 		} | ||||||
|  | 		return e | ||||||
|  | 	} | ||||||
|  | 	for _, xattr := range xattrKeys { | ||||||
|  | 		data, err := sysx.LGetxattr(src, xattr) | ||||||
|  | 		if err != nil { | ||||||
|  | 			e := errors.Wrapf(err, "failed to get xattr %q on %s", xattr, src) | ||||||
|  | 			if xeh != nil { | ||||||
|  | 				if e = xeh(dst, src, xattr, e); e == nil { | ||||||
|  | 					continue | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			return e | ||||||
|  | 		} | ||||||
|  | 		if err := sysx.LSetxattr(dst, xattr, data, 0); err != nil { | ||||||
|  | 			e := errors.Wrapf(err, "failed to set xattr %q on %s", xattr, dst) | ||||||
|  | 			if xeh != nil { | ||||||
|  | 				if e = xeh(dst, src, xattr, e); e == nil { | ||||||
|  | 					continue | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			return e | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func copyDevice(dst string, fi os.FileInfo) error { | ||||||
|  | 	st, ok := fi.Sys().(*syscall.Stat_t) | ||||||
|  | 	if !ok { | ||||||
|  | 		return errors.New("unsupported stat type") | ||||||
|  | 	} | ||||||
|  | 	return unix.Mknod(dst, uint32(fi.Mode()), int(st.Rdev)) | ||||||
|  | } | ||||||
							
								
								
									
										49
									
								
								vendor/github.com/containerd/continuity/fs/copy_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								vendor/github.com/containerd/continuity/fs/copy_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,49 @@ | |||||||
|  | /* | ||||||
|  |    Copyright The containerd Authors. | ||||||
|  |  | ||||||
|  |    Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |    you may not use this file except in compliance with the License. | ||||||
|  |    You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |        http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |    Unless required by applicable law or agreed to in writing, software | ||||||
|  |    distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |    See the License for the specific language governing permissions and | ||||||
|  |    limitations under the License. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | package fs | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"io" | ||||||
|  | 	"os" | ||||||
|  |  | ||||||
|  | 	"github.com/pkg/errors" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func copyFileInfo(fi os.FileInfo, name string) error { | ||||||
|  | 	if err := os.Chmod(name, fi.Mode()); err != nil { | ||||||
|  | 		return errors.Wrapf(err, "failed to chmod %s", name) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// TODO: copy windows specific metadata | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func copyFileContent(dst, src *os.File) error { | ||||||
|  | 	buf := bufferPool.Get().(*[]byte) | ||||||
|  | 	_, err := io.CopyBuffer(dst, src, *buf) | ||||||
|  | 	bufferPool.Put(buf) | ||||||
|  | 	return err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func copyXAttrs(dst, src string, xeh XAttrErrorHandler) error { | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func copyDevice(dst string, fi os.FileInfo) error { | ||||||
|  | 	return errors.New("device copy not supported") | ||||||
|  | } | ||||||
							
								
								
									
										326
									
								
								vendor/github.com/containerd/continuity/fs/diff.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										326
									
								
								vendor/github.com/containerd/continuity/fs/diff.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,326 @@ | |||||||
|  | /* | ||||||
|  |    Copyright The containerd Authors. | ||||||
|  |  | ||||||
|  |    Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |    you may not use this file except in compliance with the License. | ||||||
|  |    You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |        http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |    Unless required by applicable law or agreed to in writing, software | ||||||
|  |    distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |    See the License for the specific language governing permissions and | ||||||
|  |    limitations under the License. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | package fs | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"context" | ||||||
|  | 	"os" | ||||||
|  | 	"path/filepath" | ||||||
|  | 	"strings" | ||||||
|  |  | ||||||
|  | 	"golang.org/x/sync/errgroup" | ||||||
|  |  | ||||||
|  | 	"github.com/sirupsen/logrus" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // ChangeKind is the type of modification that | ||||||
|  | // a change is making. | ||||||
|  | type ChangeKind int | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	// ChangeKindUnmodified represents an unmodified | ||||||
|  | 	// file | ||||||
|  | 	ChangeKindUnmodified = iota | ||||||
|  |  | ||||||
|  | 	// ChangeKindAdd represents an addition of | ||||||
|  | 	// a file | ||||||
|  | 	ChangeKindAdd | ||||||
|  |  | ||||||
|  | 	// ChangeKindModify represents a change to | ||||||
|  | 	// an existing file | ||||||
|  | 	ChangeKindModify | ||||||
|  |  | ||||||
|  | 	// ChangeKindDelete represents a delete of | ||||||
|  | 	// a file | ||||||
|  | 	ChangeKindDelete | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func (k ChangeKind) String() string { | ||||||
|  | 	switch k { | ||||||
|  | 	case ChangeKindUnmodified: | ||||||
|  | 		return "unmodified" | ||||||
|  | 	case ChangeKindAdd: | ||||||
|  | 		return "add" | ||||||
|  | 	case ChangeKindModify: | ||||||
|  | 		return "modify" | ||||||
|  | 	case ChangeKindDelete: | ||||||
|  | 		return "delete" | ||||||
|  | 	default: | ||||||
|  | 		return "" | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Change represents single change between a diff and its parent. | ||||||
|  | type Change struct { | ||||||
|  | 	Kind ChangeKind | ||||||
|  | 	Path string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ChangeFunc is the type of function called for each change | ||||||
|  | // computed during a directory changes calculation. | ||||||
|  | type ChangeFunc func(ChangeKind, string, os.FileInfo, error) error | ||||||
|  |  | ||||||
|  | // Changes computes changes between two directories calling the | ||||||
|  | // given change function for each computed change. The first | ||||||
|  | // directory is intended to the base directory and second | ||||||
|  | // directory the changed directory. | ||||||
|  | // | ||||||
|  | // The change callback is called by the order of path names and | ||||||
|  | // should be appliable in that order. | ||||||
|  | //  Due to this apply ordering, the following is true | ||||||
|  | //  - Removed directory trees only create a single change for the root | ||||||
|  | //    directory removed. Remaining changes are implied. | ||||||
|  | //  - A directory which is modified to become a file will not have | ||||||
|  | //    delete entries for sub-path items, their removal is implied | ||||||
|  | //    by the removal of the parent directory. | ||||||
|  | // | ||||||
|  | // Opaque directories will not be treated specially and each file | ||||||
|  | // removed from the base directory will show up as a removal. | ||||||
|  | // | ||||||
|  | // File content comparisons will be done on files which have timestamps | ||||||
|  | // which may have been truncated. If either of the files being compared | ||||||
|  | // has a zero value nanosecond value, each byte will be compared for | ||||||
|  | // differences. If 2 files have the same seconds value but different | ||||||
|  | // nanosecond values where one of those values is zero, the files will | ||||||
|  | // be considered unchanged if the content is the same. This behavior | ||||||
|  | // is to account for timestamp truncation during archiving. | ||||||
|  | func Changes(ctx context.Context, a, b string, changeFn ChangeFunc) error { | ||||||
|  | 	if a == "" { | ||||||
|  | 		logrus.Debugf("Using single walk diff for %s", b) | ||||||
|  | 		return addDirChanges(ctx, changeFn, b) | ||||||
|  | 	} else if diffOptions := detectDirDiff(b, a); diffOptions != nil { | ||||||
|  | 		logrus.Debugf("Using single walk diff for %s from %s", diffOptions.diffDir, a) | ||||||
|  | 		return diffDirChanges(ctx, changeFn, a, diffOptions) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	logrus.Debugf("Using double walk diff for %s from %s", b, a) | ||||||
|  | 	return doubleWalkDiff(ctx, changeFn, a, b) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func addDirChanges(ctx context.Context, changeFn ChangeFunc, root string) error { | ||||||
|  | 	return filepath.Walk(root, func(path string, f os.FileInfo, err error) error { | ||||||
|  | 		if err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// Rebase path | ||||||
|  | 		path, err = filepath.Rel(root, path) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		path = filepath.Join(string(os.PathSeparator), path) | ||||||
|  |  | ||||||
|  | 		// Skip root | ||||||
|  | 		if path == string(os.PathSeparator) { | ||||||
|  | 			return nil | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		return changeFn(ChangeKindAdd, path, f, nil) | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // diffDirOptions is used when the diff can be directly calculated from | ||||||
|  | // a diff directory to its base, without walking both trees. | ||||||
|  | type diffDirOptions struct { | ||||||
|  | 	diffDir      string | ||||||
|  | 	skipChange   func(string) (bool, error) | ||||||
|  | 	deleteChange func(string, string, os.FileInfo) (string, error) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // diffDirChanges walks the diff directory and compares changes against the base. | ||||||
|  | func diffDirChanges(ctx context.Context, changeFn ChangeFunc, base string, o *diffDirOptions) error { | ||||||
|  | 	changedDirs := make(map[string]struct{}) | ||||||
|  | 	return filepath.Walk(o.diffDir, func(path string, f os.FileInfo, err error) error { | ||||||
|  | 		if err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// Rebase path | ||||||
|  | 		path, err = filepath.Rel(o.diffDir, path) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		path = filepath.Join(string(os.PathSeparator), path) | ||||||
|  |  | ||||||
|  | 		// Skip root | ||||||
|  | 		if path == string(os.PathSeparator) { | ||||||
|  | 			return nil | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// TODO: handle opaqueness, start new double walker at this | ||||||
|  | 		// location to get deletes, and skip tree in single walker | ||||||
|  |  | ||||||
|  | 		if o.skipChange != nil { | ||||||
|  | 			if skip, err := o.skipChange(path); skip { | ||||||
|  | 				return err | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		var kind ChangeKind | ||||||
|  |  | ||||||
|  | 		deletedFile, err := o.deleteChange(o.diffDir, path, f) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// Find out what kind of modification happened | ||||||
|  | 		if deletedFile != "" { | ||||||
|  | 			path = deletedFile | ||||||
|  | 			kind = ChangeKindDelete | ||||||
|  | 			f = nil | ||||||
|  | 		} else { | ||||||
|  | 			// Otherwise, the file was added | ||||||
|  | 			kind = ChangeKindAdd | ||||||
|  |  | ||||||
|  | 			// ...Unless it already existed in a base, in which case, it's a modification | ||||||
|  | 			stat, err := os.Stat(filepath.Join(base, path)) | ||||||
|  | 			if err != nil && !os.IsNotExist(err) { | ||||||
|  | 				return err | ||||||
|  | 			} | ||||||
|  | 			if err == nil { | ||||||
|  | 				// The file existed in the base, so that's a modification | ||||||
|  |  | ||||||
|  | 				// However, if it's a directory, maybe it wasn't actually modified. | ||||||
|  | 				// If you modify /foo/bar/baz, then /foo will be part of the changed files only because it's the parent of bar | ||||||
|  | 				if stat.IsDir() && f.IsDir() { | ||||||
|  | 					if f.Size() == stat.Size() && f.Mode() == stat.Mode() && sameFsTime(f.ModTime(), stat.ModTime()) { | ||||||
|  | 						// Both directories are the same, don't record the change | ||||||
|  | 						return nil | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 				kind = ChangeKindModify | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// If /foo/bar/file.txt is modified, then /foo/bar must be part of the changed files. | ||||||
|  | 		// This block is here to ensure the change is recorded even if the | ||||||
|  | 		// modify time, mode and size of the parent directory in the rw and ro layers are all equal. | ||||||
|  | 		// Check https://github.com/docker/docker/pull/13590 for details. | ||||||
|  | 		if f.IsDir() { | ||||||
|  | 			changedDirs[path] = struct{}{} | ||||||
|  | 		} | ||||||
|  | 		if kind == ChangeKindAdd || kind == ChangeKindDelete { | ||||||
|  | 			parent := filepath.Dir(path) | ||||||
|  | 			if _, ok := changedDirs[parent]; !ok && parent != "/" { | ||||||
|  | 				pi, err := os.Stat(filepath.Join(o.diffDir, parent)) | ||||||
|  | 				if err := changeFn(ChangeKindModify, parent, pi, err); err != nil { | ||||||
|  | 					return err | ||||||
|  | 				} | ||||||
|  | 				changedDirs[parent] = struct{}{} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		return changeFn(kind, path, f, nil) | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // doubleWalkDiff walks both directories to create a diff | ||||||
|  | func doubleWalkDiff(ctx context.Context, changeFn ChangeFunc, a, b string) (err error) { | ||||||
|  | 	g, ctx := errgroup.WithContext(ctx) | ||||||
|  |  | ||||||
|  | 	var ( | ||||||
|  | 		c1 = make(chan *currentPath) | ||||||
|  | 		c2 = make(chan *currentPath) | ||||||
|  |  | ||||||
|  | 		f1, f2 *currentPath | ||||||
|  | 		rmdir  string | ||||||
|  | 	) | ||||||
|  | 	g.Go(func() error { | ||||||
|  | 		defer close(c1) | ||||||
|  | 		return pathWalk(ctx, a, c1) | ||||||
|  | 	}) | ||||||
|  | 	g.Go(func() error { | ||||||
|  | 		defer close(c2) | ||||||
|  | 		return pathWalk(ctx, b, c2) | ||||||
|  | 	}) | ||||||
|  | 	g.Go(func() error { | ||||||
|  | 		for c1 != nil || c2 != nil { | ||||||
|  | 			if f1 == nil && c1 != nil { | ||||||
|  | 				f1, err = nextPath(ctx, c1) | ||||||
|  | 				if err != nil { | ||||||
|  | 					return err | ||||||
|  | 				} | ||||||
|  | 				if f1 == nil { | ||||||
|  | 					c1 = nil | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if f2 == nil && c2 != nil { | ||||||
|  | 				f2, err = nextPath(ctx, c2) | ||||||
|  | 				if err != nil { | ||||||
|  | 					return err | ||||||
|  | 				} | ||||||
|  | 				if f2 == nil { | ||||||
|  | 					c2 = nil | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			if f1 == nil && f2 == nil { | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			var f os.FileInfo | ||||||
|  | 			k, p := pathChange(f1, f2) | ||||||
|  | 			switch k { | ||||||
|  | 			case ChangeKindAdd: | ||||||
|  | 				if rmdir != "" { | ||||||
|  | 					rmdir = "" | ||||||
|  | 				} | ||||||
|  | 				f = f2.f | ||||||
|  | 				f2 = nil | ||||||
|  | 			case ChangeKindDelete: | ||||||
|  | 				// Check if this file is already removed by being | ||||||
|  | 				// under of a removed directory | ||||||
|  | 				if rmdir != "" && strings.HasPrefix(f1.path, rmdir) { | ||||||
|  | 					f1 = nil | ||||||
|  | 					continue | ||||||
|  | 				} else if f1.f.IsDir() { | ||||||
|  | 					rmdir = f1.path + string(os.PathSeparator) | ||||||
|  | 				} else if rmdir != "" { | ||||||
|  | 					rmdir = "" | ||||||
|  | 				} | ||||||
|  | 				f1 = nil | ||||||
|  | 			case ChangeKindModify: | ||||||
|  | 				same, err := sameFile(f1, f2) | ||||||
|  | 				if err != nil { | ||||||
|  | 					return err | ||||||
|  | 				} | ||||||
|  | 				if f1.f.IsDir() && !f2.f.IsDir() { | ||||||
|  | 					rmdir = f1.path + string(os.PathSeparator) | ||||||
|  | 				} else if rmdir != "" { | ||||||
|  | 					rmdir = "" | ||||||
|  | 				} | ||||||
|  | 				f = f2.f | ||||||
|  | 				f1 = nil | ||||||
|  | 				f2 = nil | ||||||
|  | 				if same { | ||||||
|  | 					if !isLinked(f) { | ||||||
|  | 						continue | ||||||
|  | 					} | ||||||
|  | 					k = ChangeKindUnmodified | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			if err := changeFn(k, p, f, nil); err != nil { | ||||||
|  | 				return err | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		return nil | ||||||
|  | 	}) | ||||||
|  |  | ||||||
|  | 	return g.Wait() | ||||||
|  | } | ||||||
							
								
								
									
										74
									
								
								vendor/github.com/containerd/continuity/fs/diff_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								vendor/github.com/containerd/continuity/fs/diff_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,74 @@ | |||||||
|  | // +build !windows | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |    Copyright The containerd Authors. | ||||||
|  |  | ||||||
|  |    Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |    you may not use this file except in compliance with the License. | ||||||
|  |    You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |        http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |    Unless required by applicable law or agreed to in writing, software | ||||||
|  |    distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |    See the License for the specific language governing permissions and | ||||||
|  |    limitations under the License. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | package fs | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"bytes" | ||||||
|  | 	"os" | ||||||
|  | 	"syscall" | ||||||
|  |  | ||||||
|  | 	"github.com/containerd/continuity/sysx" | ||||||
|  | 	"github.com/pkg/errors" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // detectDirDiff returns diff dir options if a directory could | ||||||
|  | // be found in the mount info for upper which is the direct | ||||||
|  | // diff with the provided lower directory | ||||||
|  | func detectDirDiff(upper, lower string) *diffDirOptions { | ||||||
|  | 	// TODO: get mount options for upper | ||||||
|  | 	// TODO: detect AUFS | ||||||
|  | 	// TODO: detect overlay | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // compareSysStat returns whether the stats are equivalent, | ||||||
|  | // whether the files are considered the same file, and | ||||||
|  | // an error | ||||||
|  | func compareSysStat(s1, s2 interface{}) (bool, error) { | ||||||
|  | 	ls1, ok := s1.(*syscall.Stat_t) | ||||||
|  | 	if !ok { | ||||||
|  | 		return false, nil | ||||||
|  | 	} | ||||||
|  | 	ls2, ok := s2.(*syscall.Stat_t) | ||||||
|  | 	if !ok { | ||||||
|  | 		return false, nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return ls1.Mode == ls2.Mode && ls1.Uid == ls2.Uid && ls1.Gid == ls2.Gid && ls1.Rdev == ls2.Rdev, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func compareCapabilities(p1, p2 string) (bool, error) { | ||||||
|  | 	c1, err := sysx.LGetxattr(p1, "security.capability") | ||||||
|  | 	if err != nil && err != sysx.ENODATA { | ||||||
|  | 		return false, errors.Wrapf(err, "failed to get xattr for %s", p1) | ||||||
|  | 	} | ||||||
|  | 	c2, err := sysx.LGetxattr(p2, "security.capability") | ||||||
|  | 	if err != nil && err != sysx.ENODATA { | ||||||
|  | 		return false, errors.Wrapf(err, "failed to get xattr for %s", p2) | ||||||
|  | 	} | ||||||
|  | 	return bytes.Equal(c1, c2), nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func isLinked(f os.FileInfo) bool { | ||||||
|  | 	s, ok := f.Sys().(*syscall.Stat_t) | ||||||
|  | 	if !ok { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	return !f.IsDir() && s.Nlink > 1 | ||||||
|  | } | ||||||
							
								
								
									
										48
									
								
								vendor/github.com/containerd/continuity/fs/diff_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								vendor/github.com/containerd/continuity/fs/diff_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | |||||||
|  | /* | ||||||
|  |    Copyright The containerd Authors. | ||||||
|  |  | ||||||
|  |    Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |    you may not use this file except in compliance with the License. | ||||||
|  |    You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |        http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |    Unless required by applicable law or agreed to in writing, software | ||||||
|  |    distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |    See the License for the specific language governing permissions and | ||||||
|  |    limitations under the License. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | package fs | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"os" | ||||||
|  |  | ||||||
|  | 	"golang.org/x/sys/windows" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func detectDirDiff(upper, lower string) *diffDirOptions { | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func compareSysStat(s1, s2 interface{}) (bool, error) { | ||||||
|  | 	f1, ok := s1.(windows.Win32FileAttributeData) | ||||||
|  | 	if !ok { | ||||||
|  | 		return false, nil | ||||||
|  | 	} | ||||||
|  | 	f2, ok := s2.(windows.Win32FileAttributeData) | ||||||
|  | 	if !ok { | ||||||
|  | 		return false, nil | ||||||
|  | 	} | ||||||
|  | 	return f1.FileAttributes == f2.FileAttributes, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func compareCapabilities(p1, p2 string) (bool, error) { | ||||||
|  | 	// TODO: Use windows equivalent | ||||||
|  | 	return true, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func isLinked(os.FileInfo) bool { | ||||||
|  | 	return false | ||||||
|  | } | ||||||
							
								
								
									
										103
									
								
								vendor/github.com/containerd/continuity/fs/dtype_linux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								vendor/github.com/containerd/continuity/fs/dtype_linux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,103 @@ | |||||||
|  | // +build linux | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |    Copyright The containerd Authors. | ||||||
|  |  | ||||||
|  |    Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |    you may not use this file except in compliance with the License. | ||||||
|  |    You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |        http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |    Unless required by applicable law or agreed to in writing, software | ||||||
|  |    distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |    See the License for the specific language governing permissions and | ||||||
|  |    limitations under the License. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | package fs | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"io/ioutil" | ||||||
|  | 	"os" | ||||||
|  | 	"syscall" | ||||||
|  | 	"unsafe" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func locateDummyIfEmpty(path string) (string, error) { | ||||||
|  | 	children, err := ioutil.ReadDir(path) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return "", err | ||||||
|  | 	} | ||||||
|  | 	if len(children) != 0 { | ||||||
|  | 		return "", nil | ||||||
|  | 	} | ||||||
|  | 	dummyFile, err := ioutil.TempFile(path, "fsutils-dummy") | ||||||
|  | 	if err != nil { | ||||||
|  | 		return "", err | ||||||
|  | 	} | ||||||
|  | 	name := dummyFile.Name() | ||||||
|  | 	err = dummyFile.Close() | ||||||
|  | 	return name, err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // SupportsDType returns whether the filesystem mounted on path supports d_type | ||||||
|  | func SupportsDType(path string) (bool, error) { | ||||||
|  | 	// locate dummy so that we have at least one dirent | ||||||
|  | 	dummy, err := locateDummyIfEmpty(path) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return false, err | ||||||
|  | 	} | ||||||
|  | 	if dummy != "" { | ||||||
|  | 		defer os.Remove(dummy) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	visited := 0 | ||||||
|  | 	supportsDType := true | ||||||
|  | 	fn := func(ent *syscall.Dirent) bool { | ||||||
|  | 		visited++ | ||||||
|  | 		if ent.Type == syscall.DT_UNKNOWN { | ||||||
|  | 			supportsDType = false | ||||||
|  | 			// stop iteration | ||||||
|  | 			return true | ||||||
|  | 		} | ||||||
|  | 		// continue iteration | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	if err = iterateReadDir(path, fn); err != nil { | ||||||
|  | 		return false, err | ||||||
|  | 	} | ||||||
|  | 	if visited == 0 { | ||||||
|  | 		return false, fmt.Errorf("did not hit any dirent during iteration %s", path) | ||||||
|  | 	} | ||||||
|  | 	return supportsDType, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func iterateReadDir(path string, fn func(*syscall.Dirent) bool) error { | ||||||
|  | 	d, err := os.Open(path) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	defer d.Close() | ||||||
|  | 	fd := int(d.Fd()) | ||||||
|  | 	buf := make([]byte, 4096) | ||||||
|  | 	for { | ||||||
|  | 		nbytes, err := syscall.ReadDirent(fd, buf) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 		if nbytes == 0 { | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 		for off := 0; off < nbytes; { | ||||||
|  | 			ent := (*syscall.Dirent)(unsafe.Pointer(&buf[off])) | ||||||
|  | 			if stop := fn(ent); stop { | ||||||
|  | 				return nil | ||||||
|  | 			} | ||||||
|  | 			off += int(ent.Reclen) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
							
								
								
									
										38
									
								
								vendor/github.com/containerd/continuity/fs/du.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								vendor/github.com/containerd/continuity/fs/du.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | |||||||
|  | /* | ||||||
|  |    Copyright The containerd Authors. | ||||||
|  |  | ||||||
|  |    Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |    you may not use this file except in compliance with the License. | ||||||
|  |    You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |        http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |    Unless required by applicable law or agreed to in writing, software | ||||||
|  |    distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |    See the License for the specific language governing permissions and | ||||||
|  |    limitations under the License. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | package fs | ||||||
|  |  | ||||||
|  | import "context" | ||||||
|  |  | ||||||
|  | // Usage of disk information | ||||||
|  | type Usage struct { | ||||||
|  | 	Inodes int64 | ||||||
|  | 	Size   int64 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // DiskUsage counts the number of inodes and disk usage for the resources under | ||||||
|  | // path. | ||||||
|  | func DiskUsage(ctx context.Context, roots ...string) (Usage, error) { | ||||||
|  | 	return diskUsage(ctx, roots...) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // DiffUsage counts the numbers of inodes and disk usage in the | ||||||
|  | // diff between the 2 directories. The first path is intended | ||||||
|  | // as the base directory and the second as the changed directory. | ||||||
|  | func DiffUsage(ctx context.Context, a, b string) (Usage, error) { | ||||||
|  | 	return diffUsage(ctx, a, b) | ||||||
|  | } | ||||||
							
								
								
									
										110
									
								
								vendor/github.com/containerd/continuity/fs/du_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								vendor/github.com/containerd/continuity/fs/du_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,110 @@ | |||||||
|  | // +build !windows | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |    Copyright The containerd Authors. | ||||||
|  |  | ||||||
|  |    Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |    you may not use this file except in compliance with the License. | ||||||
|  |    You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |        http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |    Unless required by applicable law or agreed to in writing, software | ||||||
|  |    distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |    See the License for the specific language governing permissions and | ||||||
|  |    limitations under the License. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | package fs | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"context" | ||||||
|  | 	"os" | ||||||
|  | 	"path/filepath" | ||||||
|  | 	"syscall" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type inode struct { | ||||||
|  | 	// TODO(stevvooe): Can probably reduce memory usage by not tracking | ||||||
|  | 	// device, but we can leave this right for now. | ||||||
|  | 	dev, ino uint64 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func newInode(stat *syscall.Stat_t) inode { | ||||||
|  | 	return inode{ | ||||||
|  | 		// Dev is uint32 on darwin/bsd, uint64 on linux/solaris | ||||||
|  | 		dev: uint64(stat.Dev), // nolint: unconvert | ||||||
|  | 		// Ino is uint32 on bsd, uint64 on darwin/linux/solaris | ||||||
|  | 		ino: uint64(stat.Ino), // nolint: unconvert | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func diskUsage(ctx context.Context, roots ...string) (Usage, error) { | ||||||
|  |  | ||||||
|  | 	var ( | ||||||
|  | 		size   int64 | ||||||
|  | 		inodes = map[inode]struct{}{} // expensive! | ||||||
|  | 	) | ||||||
|  |  | ||||||
|  | 	for _, root := range roots { | ||||||
|  | 		if err := filepath.Walk(root, func(path string, fi os.FileInfo, err error) error { | ||||||
|  | 			if err != nil { | ||||||
|  | 				return err | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			select { | ||||||
|  | 			case <-ctx.Done(): | ||||||
|  | 				return ctx.Err() | ||||||
|  | 			default: | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			inoKey := newInode(fi.Sys().(*syscall.Stat_t)) | ||||||
|  | 			if _, ok := inodes[inoKey]; !ok { | ||||||
|  | 				inodes[inoKey] = struct{}{} | ||||||
|  | 				size += fi.Size() | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			return nil | ||||||
|  | 		}); err != nil { | ||||||
|  | 			return Usage{}, err | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return Usage{ | ||||||
|  | 		Inodes: int64(len(inodes)), | ||||||
|  | 		Size:   size, | ||||||
|  | 	}, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func diffUsage(ctx context.Context, a, b string) (Usage, error) { | ||||||
|  | 	var ( | ||||||
|  | 		size   int64 | ||||||
|  | 		inodes = map[inode]struct{}{} // expensive! | ||||||
|  | 	) | ||||||
|  |  | ||||||
|  | 	if err := Changes(ctx, a, b, func(kind ChangeKind, _ string, fi os.FileInfo, err error) error { | ||||||
|  | 		if err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if kind == ChangeKindAdd || kind == ChangeKindModify { | ||||||
|  | 			inoKey := newInode(fi.Sys().(*syscall.Stat_t)) | ||||||
|  | 			if _, ok := inodes[inoKey]; !ok { | ||||||
|  | 				inodes[inoKey] = struct{}{} | ||||||
|  | 				size += fi.Size() | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			return nil | ||||||
|  |  | ||||||
|  | 		} | ||||||
|  | 		return nil | ||||||
|  | 	}); err != nil { | ||||||
|  | 		return Usage{}, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return Usage{ | ||||||
|  | 		Inodes: int64(len(inodes)), | ||||||
|  | 		Size:   size, | ||||||
|  | 	}, nil | ||||||
|  | } | ||||||
							
								
								
									
										82
									
								
								vendor/github.com/containerd/continuity/fs/du_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								vendor/github.com/containerd/continuity/fs/du_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,82 @@ | |||||||
|  | // +build windows | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |    Copyright The containerd Authors. | ||||||
|  |  | ||||||
|  |    Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |    you may not use this file except in compliance with the License. | ||||||
|  |    You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |        http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |    Unless required by applicable law or agreed to in writing, software | ||||||
|  |    distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |    See the License for the specific language governing permissions and | ||||||
|  |    limitations under the License. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | package fs | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"context" | ||||||
|  | 	"os" | ||||||
|  | 	"path/filepath" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func diskUsage(ctx context.Context, roots ...string) (Usage, error) { | ||||||
|  | 	var ( | ||||||
|  | 		size int64 | ||||||
|  | 	) | ||||||
|  |  | ||||||
|  | 	// TODO(stevvooe): Support inodes (or equivalent) for windows. | ||||||
|  |  | ||||||
|  | 	for _, root := range roots { | ||||||
|  | 		if err := filepath.Walk(root, func(path string, fi os.FileInfo, err error) error { | ||||||
|  | 			if err != nil { | ||||||
|  | 				return err | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			select { | ||||||
|  | 			case <-ctx.Done(): | ||||||
|  | 				return ctx.Err() | ||||||
|  | 			default: | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			size += fi.Size() | ||||||
|  | 			return nil | ||||||
|  | 		}); err != nil { | ||||||
|  | 			return Usage{}, err | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return Usage{ | ||||||
|  | 		Size: size, | ||||||
|  | 	}, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func diffUsage(ctx context.Context, a, b string) (Usage, error) { | ||||||
|  | 	var ( | ||||||
|  | 		size int64 | ||||||
|  | 	) | ||||||
|  |  | ||||||
|  | 	if err := Changes(ctx, a, b, func(kind ChangeKind, _ string, fi os.FileInfo, err error) error { | ||||||
|  | 		if err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if kind == ChangeKindAdd || kind == ChangeKindModify { | ||||||
|  | 			size += fi.Size() | ||||||
|  |  | ||||||
|  | 			return nil | ||||||
|  |  | ||||||
|  | 		} | ||||||
|  | 		return nil | ||||||
|  | 	}); err != nil { | ||||||
|  | 		return Usage{}, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return Usage{ | ||||||
|  | 		Size: size, | ||||||
|  | 	}, nil | ||||||
|  | } | ||||||
							
								
								
									
										43
									
								
								vendor/github.com/containerd/continuity/fs/hardlink.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								vendor/github.com/containerd/continuity/fs/hardlink.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | |||||||
|  | /* | ||||||
|  |    Copyright The containerd Authors. | ||||||
|  |  | ||||||
|  |    Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |    you may not use this file except in compliance with the License. | ||||||
|  |    You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |        http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |    Unless required by applicable law or agreed to in writing, software | ||||||
|  |    distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |    See the License for the specific language governing permissions and | ||||||
|  |    limitations under the License. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | package fs | ||||||
|  |  | ||||||
|  | import "os" | ||||||
|  |  | ||||||
|  | // GetLinkInfo returns an identifier representing the node a hardlink is pointing | ||||||
|  | // to. If the file is not hard linked then 0 will be returned. | ||||||
|  | func GetLinkInfo(fi os.FileInfo) (uint64, bool) { | ||||||
|  | 	return getLinkInfo(fi) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // getLinkSource returns a path for the given name and | ||||||
|  | // file info to its link source in the provided inode | ||||||
|  | // map. If the given file name is not in the map and | ||||||
|  | // has other links, it is added to the inode map | ||||||
|  | // to be a source for other link locations. | ||||||
|  | func getLinkSource(name string, fi os.FileInfo, inodes map[uint64]string) (string, error) { | ||||||
|  | 	inode, isHardlink := getLinkInfo(fi) | ||||||
|  | 	if !isHardlink { | ||||||
|  | 		return "", nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	path, ok := inodes[inode] | ||||||
|  | 	if !ok { | ||||||
|  | 		inodes[inode] = name | ||||||
|  | 	} | ||||||
|  | 	return path, nil | ||||||
|  | } | ||||||
							
								
								
									
										34
									
								
								vendor/github.com/containerd/continuity/fs/hardlink_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								vendor/github.com/containerd/continuity/fs/hardlink_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | |||||||
|  | // +build !windows | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |    Copyright The containerd Authors. | ||||||
|  |  | ||||||
|  |    Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |    you may not use this file except in compliance with the License. | ||||||
|  |    You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |        http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |    Unless required by applicable law or agreed to in writing, software | ||||||
|  |    distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |    See the License for the specific language governing permissions and | ||||||
|  |    limitations under the License. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | package fs | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"os" | ||||||
|  | 	"syscall" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func getLinkInfo(fi os.FileInfo) (uint64, bool) { | ||||||
|  | 	s, ok := fi.Sys().(*syscall.Stat_t) | ||||||
|  | 	if !ok { | ||||||
|  | 		return 0, false | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Ino is uint32 on bsd, uint64 on darwin/linux/solaris | ||||||
|  | 	return uint64(s.Ino), !fi.IsDir() && s.Nlink > 1 // nolint: unconvert | ||||||
|  | } | ||||||
							
								
								
									
										23
									
								
								vendor/github.com/containerd/continuity/fs/hardlink_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								vendor/github.com/containerd/continuity/fs/hardlink_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | |||||||
|  | /* | ||||||
|  |    Copyright The containerd Authors. | ||||||
|  |  | ||||||
|  |    Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |    you may not use this file except in compliance with the License. | ||||||
|  |    You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |        http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |    Unless required by applicable law or agreed to in writing, software | ||||||
|  |    distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |    See the License for the specific language governing permissions and | ||||||
|  |    limitations under the License. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | package fs | ||||||
|  |  | ||||||
|  | import "os" | ||||||
|  |  | ||||||
|  | func getLinkInfo(fi os.FileInfo) (uint64, bool) { | ||||||
|  | 	return 0, false | ||||||
|  | } | ||||||
							
								
								
									
										313
									
								
								vendor/github.com/containerd/continuity/fs/path.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										313
									
								
								vendor/github.com/containerd/continuity/fs/path.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,313 @@ | |||||||
|  | /* | ||||||
|  |    Copyright The containerd Authors. | ||||||
|  |  | ||||||
|  |    Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |    you may not use this file except in compliance with the License. | ||||||
|  |    You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |        http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |    Unless required by applicable law or agreed to in writing, software | ||||||
|  |    distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |    See the License for the specific language governing permissions and | ||||||
|  |    limitations under the License. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | package fs | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"bytes" | ||||||
|  | 	"context" | ||||||
|  | 	"io" | ||||||
|  | 	"os" | ||||||
|  | 	"path/filepath" | ||||||
|  |  | ||||||
|  | 	"github.com/pkg/errors" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | var ( | ||||||
|  | 	errTooManyLinks = errors.New("too many links") | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type currentPath struct { | ||||||
|  | 	path     string | ||||||
|  | 	f        os.FileInfo | ||||||
|  | 	fullPath string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func pathChange(lower, upper *currentPath) (ChangeKind, string) { | ||||||
|  | 	if lower == nil { | ||||||
|  | 		if upper == nil { | ||||||
|  | 			panic("cannot compare nil paths") | ||||||
|  | 		} | ||||||
|  | 		return ChangeKindAdd, upper.path | ||||||
|  | 	} | ||||||
|  | 	if upper == nil { | ||||||
|  | 		return ChangeKindDelete, lower.path | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	switch i := directoryCompare(lower.path, upper.path); { | ||||||
|  | 	case i < 0: | ||||||
|  | 		// File in lower that is not in upper | ||||||
|  | 		return ChangeKindDelete, lower.path | ||||||
|  | 	case i > 0: | ||||||
|  | 		// File in upper that is not in lower | ||||||
|  | 		return ChangeKindAdd, upper.path | ||||||
|  | 	default: | ||||||
|  | 		return ChangeKindModify, upper.path | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func directoryCompare(a, b string) int { | ||||||
|  | 	l := len(a) | ||||||
|  | 	if len(b) < l { | ||||||
|  | 		l = len(b) | ||||||
|  | 	} | ||||||
|  | 	for i := 0; i < l; i++ { | ||||||
|  | 		c1, c2 := a[i], b[i] | ||||||
|  | 		if c1 == filepath.Separator { | ||||||
|  | 			c1 = byte(0) | ||||||
|  | 		} | ||||||
|  | 		if c2 == filepath.Separator { | ||||||
|  | 			c2 = byte(0) | ||||||
|  | 		} | ||||||
|  | 		if c1 < c2 { | ||||||
|  | 			return -1 | ||||||
|  | 		} | ||||||
|  | 		if c1 > c2 { | ||||||
|  | 			return +1 | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if len(a) < len(b) { | ||||||
|  | 		return -1 | ||||||
|  | 	} | ||||||
|  | 	if len(a) > len(b) { | ||||||
|  | 		return +1 | ||||||
|  | 	} | ||||||
|  | 	return 0 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func sameFile(f1, f2 *currentPath) (bool, error) { | ||||||
|  | 	if os.SameFile(f1.f, f2.f) { | ||||||
|  | 		return true, nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	equalStat, err := compareSysStat(f1.f.Sys(), f2.f.Sys()) | ||||||
|  | 	if err != nil || !equalStat { | ||||||
|  | 		return equalStat, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if eq, err := compareCapabilities(f1.fullPath, f2.fullPath); err != nil || !eq { | ||||||
|  | 		return eq, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// If not a directory also check size, modtime, and content | ||||||
|  | 	if !f1.f.IsDir() { | ||||||
|  | 		if f1.f.Size() != f2.f.Size() { | ||||||
|  | 			return false, nil | ||||||
|  | 		} | ||||||
|  | 		t1 := f1.f.ModTime() | ||||||
|  | 		t2 := f2.f.ModTime() | ||||||
|  |  | ||||||
|  | 		if t1.Unix() != t2.Unix() { | ||||||
|  | 			return false, nil | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// If the timestamp may have been truncated in both of the | ||||||
|  | 		// files, check content of file to determine difference | ||||||
|  | 		if t1.Nanosecond() == 0 && t2.Nanosecond() == 0 { | ||||||
|  | 			var eq bool | ||||||
|  | 			if (f1.f.Mode() & os.ModeSymlink) == os.ModeSymlink { | ||||||
|  | 				eq, err = compareSymlinkTarget(f1.fullPath, f2.fullPath) | ||||||
|  | 			} else if f1.f.Size() > 0 { | ||||||
|  | 				eq, err = compareFileContent(f1.fullPath, f2.fullPath) | ||||||
|  | 			} | ||||||
|  | 			if err != nil || !eq { | ||||||
|  | 				return eq, err | ||||||
|  | 			} | ||||||
|  | 		} else if t1.Nanosecond() != t2.Nanosecond() { | ||||||
|  | 			return false, nil | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return true, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func compareSymlinkTarget(p1, p2 string) (bool, error) { | ||||||
|  | 	t1, err := os.Readlink(p1) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return false, err | ||||||
|  | 	} | ||||||
|  | 	t2, err := os.Readlink(p2) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return false, err | ||||||
|  | 	} | ||||||
|  | 	return t1 == t2, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const compareChuckSize = 32 * 1024 | ||||||
|  |  | ||||||
|  | // compareFileContent compares the content of 2 same sized files | ||||||
|  | // by comparing each byte. | ||||||
|  | func compareFileContent(p1, p2 string) (bool, error) { | ||||||
|  | 	f1, err := os.Open(p1) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return false, err | ||||||
|  | 	} | ||||||
|  | 	defer f1.Close() | ||||||
|  | 	f2, err := os.Open(p2) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return false, err | ||||||
|  | 	} | ||||||
|  | 	defer f2.Close() | ||||||
|  |  | ||||||
|  | 	b1 := make([]byte, compareChuckSize) | ||||||
|  | 	b2 := make([]byte, compareChuckSize) | ||||||
|  | 	for { | ||||||
|  | 		n1, err1 := f1.Read(b1) | ||||||
|  | 		if err1 != nil && err1 != io.EOF { | ||||||
|  | 			return false, err1 | ||||||
|  | 		} | ||||||
|  | 		n2, err2 := f2.Read(b2) | ||||||
|  | 		if err2 != nil && err2 != io.EOF { | ||||||
|  | 			return false, err2 | ||||||
|  | 		} | ||||||
|  | 		if n1 != n2 || !bytes.Equal(b1[:n1], b2[:n2]) { | ||||||
|  | 			return false, nil | ||||||
|  | 		} | ||||||
|  | 		if err1 == io.EOF && err2 == io.EOF { | ||||||
|  | 			return true, nil | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func pathWalk(ctx context.Context, root string, pathC chan<- *currentPath) error { | ||||||
|  | 	return filepath.Walk(root, func(path string, f os.FileInfo, err error) error { | ||||||
|  | 		if err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// Rebase path | ||||||
|  | 		path, err = filepath.Rel(root, path) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		path = filepath.Join(string(os.PathSeparator), path) | ||||||
|  |  | ||||||
|  | 		// Skip root | ||||||
|  | 		if path == string(os.PathSeparator) { | ||||||
|  | 			return nil | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		p := ¤tPath{ | ||||||
|  | 			path:     path, | ||||||
|  | 			f:        f, | ||||||
|  | 			fullPath: filepath.Join(root, path), | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		select { | ||||||
|  | 		case <-ctx.Done(): | ||||||
|  | 			return ctx.Err() | ||||||
|  | 		case pathC <- p: | ||||||
|  | 			return nil | ||||||
|  | 		} | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func nextPath(ctx context.Context, pathC <-chan *currentPath) (*currentPath, error) { | ||||||
|  | 	select { | ||||||
|  | 	case <-ctx.Done(): | ||||||
|  | 		return nil, ctx.Err() | ||||||
|  | 	case p := <-pathC: | ||||||
|  | 		return p, nil | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // RootPath joins a path with a root, evaluating and bounding any | ||||||
|  | // symlink to the root directory. | ||||||
|  | func RootPath(root, path string) (string, error) { | ||||||
|  | 	if path == "" { | ||||||
|  | 		return root, nil | ||||||
|  | 	} | ||||||
|  | 	var linksWalked int // to protect against cycles | ||||||
|  | 	for { | ||||||
|  | 		i := linksWalked | ||||||
|  | 		newpath, err := walkLinks(root, path, &linksWalked) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return "", err | ||||||
|  | 		} | ||||||
|  | 		path = newpath | ||||||
|  | 		if i == linksWalked { | ||||||
|  | 			newpath = filepath.Join("/", newpath) | ||||||
|  | 			if path == newpath { | ||||||
|  | 				return filepath.Join(root, newpath), nil | ||||||
|  | 			} | ||||||
|  | 			path = newpath | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func walkLink(root, path string, linksWalked *int) (newpath string, islink bool, err error) { | ||||||
|  | 	if *linksWalked > 255 { | ||||||
|  | 		return "", false, errTooManyLinks | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	path = filepath.Join("/", path) | ||||||
|  | 	if path == "/" { | ||||||
|  | 		return path, false, nil | ||||||
|  | 	} | ||||||
|  | 	realPath := filepath.Join(root, path) | ||||||
|  |  | ||||||
|  | 	fi, err := os.Lstat(realPath) | ||||||
|  | 	if err != nil { | ||||||
|  | 		// If path does not yet exist, treat as non-symlink | ||||||
|  | 		if os.IsNotExist(err) { | ||||||
|  | 			return path, false, nil | ||||||
|  | 		} | ||||||
|  | 		return "", false, err | ||||||
|  | 	} | ||||||
|  | 	if fi.Mode()&os.ModeSymlink == 0 { | ||||||
|  | 		return path, false, nil | ||||||
|  | 	} | ||||||
|  | 	newpath, err = os.Readlink(realPath) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return "", false, err | ||||||
|  | 	} | ||||||
|  | 	*linksWalked++ | ||||||
|  | 	return newpath, true, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func walkLinks(root, path string, linksWalked *int) (string, error) { | ||||||
|  | 	switch dir, file := filepath.Split(path); { | ||||||
|  | 	case dir == "": | ||||||
|  | 		newpath, _, err := walkLink(root, file, linksWalked) | ||||||
|  | 		return newpath, err | ||||||
|  | 	case file == "": | ||||||
|  | 		if os.IsPathSeparator(dir[len(dir)-1]) { | ||||||
|  | 			if dir == "/" { | ||||||
|  | 				return dir, nil | ||||||
|  | 			} | ||||||
|  | 			return walkLinks(root, dir[:len(dir)-1], linksWalked) | ||||||
|  | 		} | ||||||
|  | 		newpath, _, err := walkLink(root, dir, linksWalked) | ||||||
|  | 		return newpath, err | ||||||
|  | 	default: | ||||||
|  | 		newdir, err := walkLinks(root, dir, linksWalked) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return "", err | ||||||
|  | 		} | ||||||
|  | 		newpath, islink, err := walkLink(root, filepath.Join(newdir, file), linksWalked) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return "", err | ||||||
|  | 		} | ||||||
|  | 		if !islink { | ||||||
|  | 			return newpath, nil | ||||||
|  | 		} | ||||||
|  | 		if filepath.IsAbs(newpath) { | ||||||
|  | 			return newpath, nil | ||||||
|  | 		} | ||||||
|  | 		return filepath.Join(newdir, newpath), nil | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										44
									
								
								vendor/github.com/containerd/continuity/fs/stat_bsd.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								vendor/github.com/containerd/continuity/fs/stat_bsd.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,44 @@ | |||||||
|  | // +build darwin freebsd | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |    Copyright The containerd Authors. | ||||||
|  |  | ||||||
|  |    Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |    you may not use this file except in compliance with the License. | ||||||
|  |    You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |        http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |    Unless required by applicable law or agreed to in writing, software | ||||||
|  |    distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |    See the License for the specific language governing permissions and | ||||||
|  |    limitations under the License. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | package fs | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"syscall" | ||||||
|  | 	"time" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // StatAtime returns the access time from a stat struct | ||||||
|  | func StatAtime(st *syscall.Stat_t) syscall.Timespec { | ||||||
|  | 	return st.Atimespec | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // StatCtime returns the created time from a stat struct | ||||||
|  | func StatCtime(st *syscall.Stat_t) syscall.Timespec { | ||||||
|  | 	return st.Ctimespec | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // StatMtime returns the modified time from a stat struct | ||||||
|  | func StatMtime(st *syscall.Stat_t) syscall.Timespec { | ||||||
|  | 	return st.Mtimespec | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // StatATimeAsTime returns the access time as a time.Time | ||||||
|  | func StatATimeAsTime(st *syscall.Stat_t) time.Time { | ||||||
|  | 	return time.Unix(int64(st.Atimespec.Sec), int64(st.Atimespec.Nsec)) // nolint: unconvert | ||||||
|  | } | ||||||
							
								
								
									
										43
									
								
								vendor/github.com/containerd/continuity/fs/stat_linux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								vendor/github.com/containerd/continuity/fs/stat_linux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | |||||||
|  | /* | ||||||
|  |    Copyright The containerd Authors. | ||||||
|  |  | ||||||
|  |    Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |    you may not use this file except in compliance with the License. | ||||||
|  |    You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |        http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |    Unless required by applicable law or agreed to in writing, software | ||||||
|  |    distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |    See the License for the specific language governing permissions and | ||||||
|  |    limitations under the License. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | package fs | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"syscall" | ||||||
|  | 	"time" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // StatAtime returns the Atim | ||||||
|  | func StatAtime(st *syscall.Stat_t) syscall.Timespec { | ||||||
|  | 	return st.Atim | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // StatCtime returns the Ctim | ||||||
|  | func StatCtime(st *syscall.Stat_t) syscall.Timespec { | ||||||
|  | 	return st.Ctim | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // StatMtime returns the Mtim | ||||||
|  | func StatMtime(st *syscall.Stat_t) syscall.Timespec { | ||||||
|  | 	return st.Mtim | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // StatATimeAsTime returns st.Atim as a time.Time | ||||||
|  | func StatATimeAsTime(st *syscall.Stat_t) time.Time { | ||||||
|  | 	// The int64 conversions ensure the line compiles for 32-bit systems as well. | ||||||
|  | 	return time.Unix(int64(st.Atim.Sec), int64(st.Atim.Nsec)) // nolint: unconvert | ||||||
|  | } | ||||||
							
								
								
									
										29
									
								
								vendor/github.com/containerd/continuity/fs/time.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								vendor/github.com/containerd/continuity/fs/time.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | |||||||
|  | /* | ||||||
|  |    Copyright The containerd Authors. | ||||||
|  |  | ||||||
|  |    Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |    you may not use this file except in compliance with the License. | ||||||
|  |    You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |        http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |    Unless required by applicable law or agreed to in writing, software | ||||||
|  |    distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |    See the License for the specific language governing permissions and | ||||||
|  |    limitations under the License. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | package fs | ||||||
|  |  | ||||||
|  | import "time" | ||||||
|  |  | ||||||
|  | // Gnu tar and the go tar writer don't have sub-second mtime | ||||||
|  | // precision, which is problematic when we apply changes via tar | ||||||
|  | // files, we handle this by comparing for exact times, *or* same | ||||||
|  | // second count and either a or b having exactly 0 nanoseconds | ||||||
|  | func sameFsTime(a, b time.Time) bool { | ||||||
|  | 	return a == b || | ||||||
|  | 		(a.Unix() == b.Unix() && | ||||||
|  | 			(a.Nanosecond() == 0 || b.Nanosecond() == 0)) | ||||||
|  | } | ||||||
							
								
								
									
										101
									
								
								vendor/github.com/containerd/continuity/pathdriver/path_driver.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								vendor/github.com/containerd/continuity/pathdriver/path_driver.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,101 @@ | |||||||
|  | /* | ||||||
|  |    Copyright The containerd Authors. | ||||||
|  |  | ||||||
|  |    Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |    you may not use this file except in compliance with the License. | ||||||
|  |    You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |        http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |    Unless required by applicable law or agreed to in writing, software | ||||||
|  |    distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |    See the License for the specific language governing permissions and | ||||||
|  |    limitations under the License. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | package pathdriver | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"path/filepath" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // PathDriver provides all of the path manipulation functions in a common | ||||||
|  | // interface. The context should call these and never use the `filepath` | ||||||
|  | // package or any other package to manipulate paths. | ||||||
|  | type PathDriver interface { | ||||||
|  | 	Join(paths ...string) string | ||||||
|  | 	IsAbs(path string) bool | ||||||
|  | 	Rel(base, target string) (string, error) | ||||||
|  | 	Base(path string) string | ||||||
|  | 	Dir(path string) string | ||||||
|  | 	Clean(path string) string | ||||||
|  | 	Split(path string) (dir, file string) | ||||||
|  | 	Separator() byte | ||||||
|  | 	Abs(path string) (string, error) | ||||||
|  | 	Walk(string, filepath.WalkFunc) error | ||||||
|  | 	FromSlash(path string) string | ||||||
|  | 	ToSlash(path string) string | ||||||
|  | 	Match(pattern, name string) (matched bool, err error) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // pathDriver is a simple default implementation calls the filepath package. | ||||||
|  | type pathDriver struct{} | ||||||
|  |  | ||||||
|  | // LocalPathDriver is the exported pathDriver struct for convenience. | ||||||
|  | var LocalPathDriver PathDriver = &pathDriver{} | ||||||
|  |  | ||||||
|  | func (*pathDriver) Join(paths ...string) string { | ||||||
|  | 	return filepath.Join(paths...) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (*pathDriver) IsAbs(path string) bool { | ||||||
|  | 	return filepath.IsAbs(path) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (*pathDriver) Rel(base, target string) (string, error) { | ||||||
|  | 	return filepath.Rel(base, target) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (*pathDriver) Base(path string) string { | ||||||
|  | 	return filepath.Base(path) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (*pathDriver) Dir(path string) string { | ||||||
|  | 	return filepath.Dir(path) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (*pathDriver) Clean(path string) string { | ||||||
|  | 	return filepath.Clean(path) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (*pathDriver) Split(path string) (dir, file string) { | ||||||
|  | 	return filepath.Split(path) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (*pathDriver) Separator() byte { | ||||||
|  | 	return filepath.Separator | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (*pathDriver) Abs(path string) (string, error) { | ||||||
|  | 	return filepath.Abs(path) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Note that filepath.Walk calls os.Stat, so if the context wants to | ||||||
|  | // to call Driver.Stat() for Walk, they need to create a new struct that | ||||||
|  | // overrides this method. | ||||||
|  | func (*pathDriver) Walk(root string, walkFn filepath.WalkFunc) error { | ||||||
|  | 	return filepath.Walk(root, walkFn) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (*pathDriver) FromSlash(path string) string { | ||||||
|  | 	return filepath.FromSlash(path) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (*pathDriver) ToSlash(path string) string { | ||||||
|  | 	return filepath.ToSlash(path) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (*pathDriver) Match(pattern, name string) (bool, error) { | ||||||
|  | 	return filepath.Match(pattern, name) | ||||||
|  | } | ||||||
							
								
								
									
										26
									
								
								vendor/github.com/containerd/continuity/syscallx/syscall_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								vendor/github.com/containerd/continuity/syscallx/syscall_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | |||||||
|  | // +build !windows | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |    Copyright The containerd Authors. | ||||||
|  |  | ||||||
|  |    Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |    you may not use this file except in compliance with the License. | ||||||
|  |    You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |        http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |    Unless required by applicable law or agreed to in writing, software | ||||||
|  |    distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |    See the License for the specific language governing permissions and | ||||||
|  |    limitations under the License. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | package syscallx | ||||||
|  |  | ||||||
|  | import "syscall" | ||||||
|  |  | ||||||
|  | // Readlink returns the destination of the named symbolic link. | ||||||
|  | func Readlink(path string, buf []byte) (n int, err error) { | ||||||
|  | 	return syscall.Readlink(path, buf) | ||||||
|  | } | ||||||
							
								
								
									
										112
									
								
								vendor/github.com/containerd/continuity/syscallx/syscall_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								vendor/github.com/containerd/continuity/syscallx/syscall_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,112 @@ | |||||||
|  | /* | ||||||
|  |    Copyright The containerd Authors. | ||||||
|  |  | ||||||
|  |    Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |    you may not use this file except in compliance with the License. | ||||||
|  |    You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |        http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |    Unless required by applicable law or agreed to in writing, software | ||||||
|  |    distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |    See the License for the specific language governing permissions and | ||||||
|  |    limitations under the License. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | package syscallx | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"syscall" | ||||||
|  | 	"unsafe" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type reparseDataBuffer struct { | ||||||
|  | 	ReparseTag        uint32 | ||||||
|  | 	ReparseDataLength uint16 | ||||||
|  | 	Reserved          uint16 | ||||||
|  |  | ||||||
|  | 	// GenericReparseBuffer | ||||||
|  | 	reparseBuffer byte | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type mountPointReparseBuffer struct { | ||||||
|  | 	SubstituteNameOffset uint16 | ||||||
|  | 	SubstituteNameLength uint16 | ||||||
|  | 	PrintNameOffset      uint16 | ||||||
|  | 	PrintNameLength      uint16 | ||||||
|  | 	PathBuffer           [1]uint16 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type symbolicLinkReparseBuffer struct { | ||||||
|  | 	SubstituteNameOffset uint16 | ||||||
|  | 	SubstituteNameLength uint16 | ||||||
|  | 	PrintNameOffset      uint16 | ||||||
|  | 	PrintNameLength      uint16 | ||||||
|  | 	Flags                uint32 | ||||||
|  | 	PathBuffer           [1]uint16 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	_IO_REPARSE_TAG_MOUNT_POINT = 0xA0000003 | ||||||
|  | 	_SYMLINK_FLAG_RELATIVE      = 1 | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // Readlink returns the destination of the named symbolic link. | ||||||
|  | func Readlink(path string, buf []byte) (n int, err error) { | ||||||
|  | 	fd, err := syscall.CreateFile(syscall.StringToUTF16Ptr(path), syscall.GENERIC_READ, 0, nil, syscall.OPEN_EXISTING, | ||||||
|  | 		syscall.FILE_FLAG_OPEN_REPARSE_POINT|syscall.FILE_FLAG_BACKUP_SEMANTICS, 0) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return -1, err | ||||||
|  | 	} | ||||||
|  | 	defer syscall.CloseHandle(fd) | ||||||
|  |  | ||||||
|  | 	rdbbuf := make([]byte, syscall.MAXIMUM_REPARSE_DATA_BUFFER_SIZE) | ||||||
|  | 	var bytesReturned uint32 | ||||||
|  | 	err = syscall.DeviceIoControl(fd, syscall.FSCTL_GET_REPARSE_POINT, nil, 0, &rdbbuf[0], uint32(len(rdbbuf)), &bytesReturned, nil) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return -1, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	rdb := (*reparseDataBuffer)(unsafe.Pointer(&rdbbuf[0])) | ||||||
|  | 	var s string | ||||||
|  | 	switch rdb.ReparseTag { | ||||||
|  | 	case syscall.IO_REPARSE_TAG_SYMLINK: | ||||||
|  | 		data := (*symbolicLinkReparseBuffer)(unsafe.Pointer(&rdb.reparseBuffer)) | ||||||
|  | 		p := (*[0xffff]uint16)(unsafe.Pointer(&data.PathBuffer[0])) | ||||||
|  | 		s = syscall.UTF16ToString(p[data.SubstituteNameOffset/2 : (data.SubstituteNameOffset+data.SubstituteNameLength)/2]) | ||||||
|  | 		if data.Flags&_SYMLINK_FLAG_RELATIVE == 0 { | ||||||
|  | 			if len(s) >= 4 && s[:4] == `\??\` { | ||||||
|  | 				s = s[4:] | ||||||
|  | 				switch { | ||||||
|  | 				case len(s) >= 2 && s[1] == ':': // \??\C:\foo\bar | ||||||
|  | 					// do nothing | ||||||
|  | 				case len(s) >= 4 && s[:4] == `UNC\`: // \??\UNC\foo\bar | ||||||
|  | 					s = `\\` + s[4:] | ||||||
|  | 				default: | ||||||
|  | 					// unexpected; do nothing | ||||||
|  | 				} | ||||||
|  | 			} else { | ||||||
|  | 				// unexpected; do nothing | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	case _IO_REPARSE_TAG_MOUNT_POINT: | ||||||
|  | 		data := (*mountPointReparseBuffer)(unsafe.Pointer(&rdb.reparseBuffer)) | ||||||
|  | 		p := (*[0xffff]uint16)(unsafe.Pointer(&data.PathBuffer[0])) | ||||||
|  | 		s = syscall.UTF16ToString(p[data.SubstituteNameOffset/2 : (data.SubstituteNameOffset+data.SubstituteNameLength)/2]) | ||||||
|  | 		if len(s) >= 4 && s[:4] == `\??\` { // \??\C:\foo\bar | ||||||
|  | 			if len(s) < 48 || s[:11] != `\??\Volume{` { | ||||||
|  | 				s = s[4:] | ||||||
|  | 			} | ||||||
|  | 		} else { | ||||||
|  | 			// unexpected; do nothing | ||||||
|  | 		} | ||||||
|  | 	default: | ||||||
|  | 		// the path is not a symlink or junction but another type of reparse | ||||||
|  | 		// point | ||||||
|  | 		return -1, syscall.ENOENT | ||||||
|  | 	} | ||||||
|  | 	n = copy(buf, []byte(s)) | ||||||
|  |  | ||||||
|  | 	return n, nil | ||||||
|  | } | ||||||
							
								
								
									
										3
									
								
								vendor/github.com/containerd/continuity/sysx/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								vendor/github.com/containerd/continuity/sysx/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | |||||||
|  | This package is for internal use only. It is intended to only have | ||||||
|  | temporary changes before they are upstreamed to golang.org/x/sys/ | ||||||
|  | (a.k.a. https://github.com/golang/sys). | ||||||
							
								
								
									
										128
									
								
								vendor/github.com/containerd/continuity/sysx/file_posix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								vendor/github.com/containerd/continuity/sysx/file_posix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,128 @@ | |||||||
|  | /* | ||||||
|  |    Copyright The containerd Authors. | ||||||
|  |  | ||||||
|  |    Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |    you may not use this file except in compliance with the License. | ||||||
|  |    You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |        http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |    Unless required by applicable law or agreed to in writing, software | ||||||
|  |    distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |    See the License for the specific language governing permissions and | ||||||
|  |    limitations under the License. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | package sysx | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"os" | ||||||
|  | 	"path/filepath" | ||||||
|  |  | ||||||
|  | 	"github.com/containerd/continuity/syscallx" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // Readlink returns the destination of the named symbolic link. | ||||||
|  | // If there is an error, it will be of type *PathError. | ||||||
|  | func Readlink(name string) (string, error) { | ||||||
|  | 	for len := 128; ; len *= 2 { | ||||||
|  | 		b := make([]byte, len) | ||||||
|  | 		n, e := fixCount(syscallx.Readlink(fixLongPath(name), b)) | ||||||
|  | 		if e != nil { | ||||||
|  | 			return "", &os.PathError{Op: "readlink", Path: name, Err: e} | ||||||
|  | 		} | ||||||
|  | 		if n < len { | ||||||
|  | 			return string(b[0:n]), nil | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Many functions in package syscall return a count of -1 instead of 0. | ||||||
|  | // Using fixCount(call()) instead of call() corrects the count. | ||||||
|  | func fixCount(n int, err error) (int, error) { | ||||||
|  | 	if n < 0 { | ||||||
|  | 		n = 0 | ||||||
|  | 	} | ||||||
|  | 	return n, err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // fixLongPath returns the extended-length (\\?\-prefixed) form of | ||||||
|  | // path when needed, in order to avoid the default 260 character file | ||||||
|  | // path limit imposed by Windows. If path is not easily converted to | ||||||
|  | // the extended-length form (for example, if path is a relative path | ||||||
|  | // or contains .. elements), or is short enough, fixLongPath returns | ||||||
|  | // path unmodified. | ||||||
|  | // | ||||||
|  | // See https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx#maxpath | ||||||
|  | func fixLongPath(path string) string { | ||||||
|  | 	// Do nothing (and don't allocate) if the path is "short". | ||||||
|  | 	// Empirically (at least on the Windows Server 2013 builder), | ||||||
|  | 	// the kernel is arbitrarily okay with < 248 bytes. That | ||||||
|  | 	// matches what the docs above say: | ||||||
|  | 	// "When using an API to create a directory, the specified | ||||||
|  | 	// path cannot be so long that you cannot append an 8.3 file | ||||||
|  | 	// name (that is, the directory name cannot exceed MAX_PATH | ||||||
|  | 	// minus 12)." Since MAX_PATH is 260, 260 - 12 = 248. | ||||||
|  | 	// | ||||||
|  | 	// The MSDN docs appear to say that a normal path that is 248 bytes long | ||||||
|  | 	// will work; empirically the path must be less then 248 bytes long. | ||||||
|  | 	if len(path) < 248 { | ||||||
|  | 		// Don't fix. (This is how Go 1.7 and earlier worked, | ||||||
|  | 		// not automatically generating the \\?\ form) | ||||||
|  | 		return path | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// The extended form begins with \\?\, as in | ||||||
|  | 	// \\?\c:\windows\foo.txt or \\?\UNC\server\share\foo.txt. | ||||||
|  | 	// The extended form disables evaluation of . and .. path | ||||||
|  | 	// elements and disables the interpretation of / as equivalent | ||||||
|  | 	// to \. The conversion here rewrites / to \ and elides | ||||||
|  | 	// . elements as well as trailing or duplicate separators. For | ||||||
|  | 	// simplicity it avoids the conversion entirely for relative | ||||||
|  | 	// paths or paths containing .. elements. For now, | ||||||
|  | 	// \\server\share paths are not converted to | ||||||
|  | 	// \\?\UNC\server\share paths because the rules for doing so | ||||||
|  | 	// are less well-specified. | ||||||
|  | 	if len(path) >= 2 && path[:2] == `\\` { | ||||||
|  | 		// Don't canonicalize UNC paths. | ||||||
|  | 		return path | ||||||
|  | 	} | ||||||
|  | 	if !filepath.IsAbs(path) { | ||||||
|  | 		// Relative path | ||||||
|  | 		return path | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	const prefix = `\\?` | ||||||
|  |  | ||||||
|  | 	pathbuf := make([]byte, len(prefix)+len(path)+len(`\`)) | ||||||
|  | 	copy(pathbuf, prefix) | ||||||
|  | 	n := len(path) | ||||||
|  | 	r, w := 0, len(prefix) | ||||||
|  | 	for r < n { | ||||||
|  | 		switch { | ||||||
|  | 		case os.IsPathSeparator(path[r]): | ||||||
|  | 			// empty block | ||||||
|  | 			r++ | ||||||
|  | 		case path[r] == '.' && (r+1 == n || os.IsPathSeparator(path[r+1])): | ||||||
|  | 			// /./ | ||||||
|  | 			r++ | ||||||
|  | 		case r+1 < n && path[r] == '.' && path[r+1] == '.' && (r+2 == n || os.IsPathSeparator(path[r+2])): | ||||||
|  | 			// /../ is currently unhandled | ||||||
|  | 			return path | ||||||
|  | 		default: | ||||||
|  | 			pathbuf[w] = '\\' | ||||||
|  | 			w++ | ||||||
|  | 			for ; r < n && !os.IsPathSeparator(path[r]); r++ { | ||||||
|  | 				pathbuf[w] = path[r] | ||||||
|  | 				w++ | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	// A drive's root directory needs a trailing \ | ||||||
|  | 	if w == len(`\\?\c:`) { | ||||||
|  | 		pathbuf[w] = '\\' | ||||||
|  | 		w++ | ||||||
|  | 	} | ||||||
|  | 	return string(pathbuf[:w]) | ||||||
|  | } | ||||||
							
								
								
									
										52
									
								
								vendor/github.com/containerd/continuity/sysx/generate.sh
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								vendor/github.com/containerd/continuity/sysx/generate.sh
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,52 @@ | |||||||
|  | #!/bin/bash | ||||||
|  |  | ||||||
|  | #   Copyright The containerd Authors. | ||||||
|  |  | ||||||
|  | #   Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  | #   you may not use this file except in compliance with the License. | ||||||
|  | #   You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  | #       http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  | #   Unless required by applicable law or agreed to in writing, software | ||||||
|  | #   distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  | #   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  | #   See the License for the specific language governing permissions and | ||||||
|  | #   limitations under the License. | ||||||
|  |  | ||||||
|  |  | ||||||
|  | set -e | ||||||
|  |  | ||||||
|  | mksyscall="$(go env GOROOT)/src/syscall/mksyscall.pl" | ||||||
|  |  | ||||||
|  | fix() { | ||||||
|  | 	sed 's,^package syscall$,package sysx,' \ | ||||||
|  | 		| sed 's,^import "unsafe"$,import (\n\t"syscall"\n\t"unsafe"\n),' \ | ||||||
|  | 		| gofmt -r='BytePtrFromString -> syscall.BytePtrFromString' \ | ||||||
|  | 		| gofmt -r='Syscall6 -> syscall.Syscall6' \ | ||||||
|  | 		| gofmt -r='Syscall -> syscall.Syscall' \ | ||||||
|  | 		| gofmt -r='SYS_GETXATTR -> syscall.SYS_GETXATTR' \ | ||||||
|  | 		| gofmt -r='SYS_LISTXATTR -> syscall.SYS_LISTXATTR' \ | ||||||
|  | 		| gofmt -r='SYS_SETXATTR -> syscall.SYS_SETXATTR' \ | ||||||
|  | 		| gofmt -r='SYS_REMOVEXATTR -> syscall.SYS_REMOVEXATTR' \ | ||||||
|  | 		| gofmt -r='SYS_LGETXATTR -> syscall.SYS_LGETXATTR' \ | ||||||
|  | 		| gofmt -r='SYS_LLISTXATTR -> syscall.SYS_LLISTXATTR' \ | ||||||
|  | 		| gofmt -r='SYS_LSETXATTR -> syscall.SYS_LSETXATTR' \ | ||||||
|  | 		| gofmt -r='SYS_LREMOVEXATTR -> syscall.SYS_LREMOVEXATTR' | ||||||
|  | } | ||||||
|  |  | ||||||
|  | if [ "$GOARCH" == "" ] || [ "$GOOS" == "" ]; then | ||||||
|  | 	echo "Must specify \$GOARCH and \$GOOS" | ||||||
|  | 	exit 1 | ||||||
|  | fi | ||||||
|  |  | ||||||
|  | mkargs="" | ||||||
|  |  | ||||||
|  | if [ "$GOARCH" == "386" ] || [ "$GOARCH" == "arm" ]; then | ||||||
|  | 	mkargs="-l32" | ||||||
|  | fi | ||||||
|  |  | ||||||
|  | for f in "$@"; do | ||||||
|  | 	$mksyscall $mkargs "${f}_${GOOS}.go" | fix > "${f}_${GOOS}_${GOARCH}.go" | ||||||
|  | done | ||||||
|  |  | ||||||
							
								
								
									
										23
									
								
								vendor/github.com/containerd/continuity/sysx/nodata_linux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								vendor/github.com/containerd/continuity/sysx/nodata_linux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | |||||||
|  | /* | ||||||
|  |    Copyright The containerd Authors. | ||||||
|  |  | ||||||
|  |    Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |    you may not use this file except in compliance with the License. | ||||||
|  |    You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |        http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |    Unless required by applicable law or agreed to in writing, software | ||||||
|  |    distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |    See the License for the specific language governing permissions and | ||||||
|  |    limitations under the License. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | package sysx | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"syscall" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | const ENODATA = syscall.ENODATA | ||||||
							
								
								
									
										24
									
								
								vendor/github.com/containerd/continuity/sysx/nodata_solaris.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								vendor/github.com/containerd/continuity/sysx/nodata_solaris.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | |||||||
|  | /* | ||||||
|  |    Copyright The containerd Authors. | ||||||
|  |  | ||||||
|  |    Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |    you may not use this file except in compliance with the License. | ||||||
|  |    You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |        http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |    Unless required by applicable law or agreed to in writing, software | ||||||
|  |    distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |    See the License for the specific language governing permissions and | ||||||
|  |    limitations under the License. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | package sysx | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"syscall" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // This should actually be a set that contains ENOENT and EPERM | ||||||
|  | const ENODATA = syscall.ENOENT | ||||||
							
								
								
									
										25
									
								
								vendor/github.com/containerd/continuity/sysx/nodata_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								vendor/github.com/containerd/continuity/sysx/nodata_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | |||||||
|  | // +build darwin freebsd | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |    Copyright The containerd Authors. | ||||||
|  |  | ||||||
|  |    Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |    you may not use this file except in compliance with the License. | ||||||
|  |    You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |        http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |    Unless required by applicable law or agreed to in writing, software | ||||||
|  |    distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |    See the License for the specific language governing permissions and | ||||||
|  |    limitations under the License. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | package sysx | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"syscall" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | const ENODATA = syscall.ENOATTR | ||||||
							
								
								
									
										125
									
								
								vendor/github.com/containerd/continuity/sysx/xattr.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								vendor/github.com/containerd/continuity/sysx/xattr.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,125 @@ | |||||||
|  | // +build linux darwin | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |    Copyright The containerd Authors. | ||||||
|  |  | ||||||
|  |    Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |    you may not use this file except in compliance with the License. | ||||||
|  |    You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |        http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |    Unless required by applicable law or agreed to in writing, software | ||||||
|  |    distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |    See the License for the specific language governing permissions and | ||||||
|  |    limitations under the License. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | package sysx | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"bytes" | ||||||
|  | 	"syscall" | ||||||
|  |  | ||||||
|  | 	"golang.org/x/sys/unix" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // Listxattr calls syscall listxattr and reads all content | ||||||
|  | // and returns a string array | ||||||
|  | func Listxattr(path string) ([]string, error) { | ||||||
|  | 	return listxattrAll(path, unix.Listxattr) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Removexattr calls syscall removexattr | ||||||
|  | func Removexattr(path string, attr string) (err error) { | ||||||
|  | 	return unix.Removexattr(path, attr) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Setxattr calls syscall setxattr | ||||||
|  | func Setxattr(path string, attr string, data []byte, flags int) (err error) { | ||||||
|  | 	return unix.Setxattr(path, attr, data, flags) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Getxattr calls syscall getxattr | ||||||
|  | func Getxattr(path, attr string) ([]byte, error) { | ||||||
|  | 	return getxattrAll(path, attr, unix.Getxattr) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // LListxattr lists xattrs, not following symlinks | ||||||
|  | func LListxattr(path string) ([]string, error) { | ||||||
|  | 	return listxattrAll(path, unix.Llistxattr) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // LRemovexattr removes an xattr, not following symlinks | ||||||
|  | func LRemovexattr(path string, attr string) (err error) { | ||||||
|  | 	return unix.Lremovexattr(path, attr) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // LSetxattr sets an xattr, not following symlinks | ||||||
|  | func LSetxattr(path string, attr string, data []byte, flags int) (err error) { | ||||||
|  | 	return unix.Lsetxattr(path, attr, data, flags) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // LGetxattr gets an xattr, not following symlinks | ||||||
|  | func LGetxattr(path, attr string) ([]byte, error) { | ||||||
|  | 	return getxattrAll(path, attr, unix.Lgetxattr) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const defaultXattrBufferSize = 5 | ||||||
|  |  | ||||||
|  | type listxattrFunc func(path string, dest []byte) (int, error) | ||||||
|  |  | ||||||
|  | func listxattrAll(path string, listFunc listxattrFunc) ([]string, error) { | ||||||
|  | 	var p []byte // nil on first execution | ||||||
|  |  | ||||||
|  | 	for { | ||||||
|  | 		n, err := listFunc(path, p) // first call gets buffer size. | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if n > len(p) { | ||||||
|  | 			p = make([]byte, n) | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		p = p[:n] | ||||||
|  |  | ||||||
|  | 		ps := bytes.Split(bytes.TrimSuffix(p, []byte{0}), []byte{0}) | ||||||
|  | 		var entries []string | ||||||
|  | 		for _, p := range ps { | ||||||
|  | 			s := string(p) | ||||||
|  | 			if s != "" { | ||||||
|  | 				entries = append(entries, s) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		return entries, nil | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type getxattrFunc func(string, string, []byte) (int, error) | ||||||
|  |  | ||||||
|  | func getxattrAll(path, attr string, getFunc getxattrFunc) ([]byte, error) { | ||||||
|  | 	p := make([]byte, defaultXattrBufferSize) | ||||||
|  | 	for { | ||||||
|  | 		n, err := getFunc(path, attr, p) | ||||||
|  | 		if err != nil { | ||||||
|  | 			if errno, ok := err.(syscall.Errno); ok && errno == syscall.ERANGE { | ||||||
|  | 				p = make([]byte, len(p)*2) // this can't be ideal. | ||||||
|  | 				continue                   // try again! | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// realloc to correct size and repeat | ||||||
|  | 		if n > len(p) { | ||||||
|  | 			p = make([]byte, n) | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		return p[:n], nil | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										67
									
								
								vendor/github.com/containerd/continuity/sysx/xattr_unsupported.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								vendor/github.com/containerd/continuity/sysx/xattr_unsupported.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,67 @@ | |||||||
|  | // +build !linux,!darwin | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |    Copyright The containerd Authors. | ||||||
|  |  | ||||||
|  |    Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |    you may not use this file except in compliance with the License. | ||||||
|  |    You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |        http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |    Unless required by applicable law or agreed to in writing, software | ||||||
|  |    distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |    See the License for the specific language governing permissions and | ||||||
|  |    limitations under the License. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | package sysx | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"errors" | ||||||
|  | 	"runtime" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | var unsupported = errors.New("extended attributes unsupported on " + runtime.GOOS) | ||||||
|  |  | ||||||
|  | // Listxattr calls syscall listxattr and reads all content | ||||||
|  | // and returns a string array | ||||||
|  | func Listxattr(path string) ([]string, error) { | ||||||
|  | 	return []string{}, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Removexattr calls syscall removexattr | ||||||
|  | func Removexattr(path string, attr string) (err error) { | ||||||
|  | 	return unsupported | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Setxattr calls syscall setxattr | ||||||
|  | func Setxattr(path string, attr string, data []byte, flags int) (err error) { | ||||||
|  | 	return unsupported | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Getxattr calls syscall getxattr | ||||||
|  | func Getxattr(path, attr string) ([]byte, error) { | ||||||
|  | 	return []byte{}, unsupported | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // LListxattr lists xattrs, not following symlinks | ||||||
|  | func LListxattr(path string) ([]string, error) { | ||||||
|  | 	return []string{}, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // LRemovexattr removes an xattr, not following symlinks | ||||||
|  | func LRemovexattr(path string, attr string) (err error) { | ||||||
|  | 	return unsupported | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // LSetxattr sets an xattr, not following symlinks | ||||||
|  | func LSetxattr(path string, attr string, data []byte, flags int) (err error) { | ||||||
|  | 	return unsupported | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // LGetxattr gets an xattr, not following symlinks | ||||||
|  | func LGetxattr(path, attr string) ([]byte, error) { | ||||||
|  | 	return []byte{}, nil | ||||||
|  | } | ||||||
							
								
								
									
										202
									
								
								vendor/github.com/docker/distribution/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										202
									
								
								vendor/github.com/docker/distribution/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,202 @@ | |||||||
|  | Apache License | ||||||
|  |                            Version 2.0, January 2004 | ||||||
|  |                         http://www.apache.org/licenses/ | ||||||
|  |  | ||||||
|  |    TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION | ||||||
|  |  | ||||||
|  |    1. Definitions. | ||||||
|  |  | ||||||
|  |       "License" shall mean the terms and conditions for use, reproduction, | ||||||
|  |       and distribution as defined by Sections 1 through 9 of this document. | ||||||
|  |  | ||||||
|  |       "Licensor" shall mean the copyright owner or entity authorized by | ||||||
|  |       the copyright owner that is granting the License. | ||||||
|  |  | ||||||
|  |       "Legal Entity" shall mean the union of the acting entity and all | ||||||
|  |       other entities that control, are controlled by, or are under common | ||||||
|  |       control with that entity. For the purposes of this definition, | ||||||
|  |       "control" means (i) the power, direct or indirect, to cause the | ||||||
|  |       direction or management of such entity, whether by contract or | ||||||
|  |       otherwise, or (ii) ownership of fifty percent (50%) or more of the | ||||||
|  |       outstanding shares, or (iii) beneficial ownership of such entity. | ||||||
|  |  | ||||||
|  |       "You" (or "Your") shall mean an individual or Legal Entity | ||||||
|  |       exercising permissions granted by this License. | ||||||
|  |  | ||||||
|  |       "Source" form shall mean the preferred form for making modifications, | ||||||
|  |       including but not limited to software source code, documentation | ||||||
|  |       source, and configuration files. | ||||||
|  |  | ||||||
|  |       "Object" form shall mean any form resulting from mechanical | ||||||
|  |       transformation or translation of a Source form, including but | ||||||
|  |       not limited to compiled object code, generated documentation, | ||||||
|  |       and conversions to other media types. | ||||||
|  |  | ||||||
|  |       "Work" shall mean the work of authorship, whether in Source or | ||||||
|  |       Object form, made available under the License, as indicated by a | ||||||
|  |       copyright notice that is included in or attached to the work | ||||||
|  |       (an example is provided in the Appendix below). | ||||||
|  |  | ||||||
|  |       "Derivative Works" shall mean any work, whether in Source or Object | ||||||
|  |       form, that is based on (or derived from) the Work and for which the | ||||||
|  |       editorial revisions, annotations, elaborations, or other modifications | ||||||
|  |       represent, as a whole, an original work of authorship. For the purposes | ||||||
|  |       of this License, Derivative Works shall not include works that remain | ||||||
|  |       separable from, or merely link (or bind by name) to the interfaces of, | ||||||
|  |       the Work and Derivative Works thereof. | ||||||
|  |  | ||||||
|  |       "Contribution" shall mean any work of authorship, including | ||||||
|  |       the original version of the Work and any modifications or additions | ||||||
|  |       to that Work or Derivative Works thereof, that is intentionally | ||||||
|  |       submitted to Licensor for inclusion in the Work by the copyright owner | ||||||
|  |       or by an individual or Legal Entity authorized to submit on behalf of | ||||||
|  |       the copyright owner. For the purposes of this definition, "submitted" | ||||||
|  |       means any form of electronic, verbal, or written communication sent | ||||||
|  |       to the Licensor or its representatives, including but not limited to | ||||||
|  |       communication on electronic mailing lists, source code control systems, | ||||||
|  |       and issue tracking systems that are managed by, or on behalf of, the | ||||||
|  |       Licensor for the purpose of discussing and improving the Work, but | ||||||
|  |       excluding communication that is conspicuously marked or otherwise | ||||||
|  |       designated in writing by the copyright owner as "Not a Contribution." | ||||||
|  |  | ||||||
|  |       "Contributor" shall mean Licensor and any individual or Legal Entity | ||||||
|  |       on behalf of whom a Contribution has been received by Licensor and | ||||||
|  |       subsequently incorporated within the Work. | ||||||
|  |  | ||||||
|  |    2. Grant of Copyright License. Subject to the terms and conditions of | ||||||
|  |       this License, each Contributor hereby grants to You a perpetual, | ||||||
|  |       worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||||||
|  |       copyright license to reproduce, prepare Derivative Works of, | ||||||
|  |       publicly display, publicly perform, sublicense, and distribute the | ||||||
|  |       Work and such Derivative Works in Source or Object form. | ||||||
|  |  | ||||||
|  |    3. Grant of Patent License. Subject to the terms and conditions of | ||||||
|  |       this License, each Contributor hereby grants to You a perpetual, | ||||||
|  |       worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||||||
|  |       (except as stated in this section) patent license to make, have made, | ||||||
|  |       use, offer to sell, sell, import, and otherwise transfer the Work, | ||||||
|  |       where such license applies only to those patent claims licensable | ||||||
|  |       by such Contributor that are necessarily infringed by their | ||||||
|  |       Contribution(s) alone or by combination of their Contribution(s) | ||||||
|  |       with the Work to which such Contribution(s) was submitted. If You | ||||||
|  |       institute patent litigation against any entity (including a | ||||||
|  |       cross-claim or counterclaim in a lawsuit) alleging that the Work | ||||||
|  |       or a Contribution incorporated within the Work constitutes direct | ||||||
|  |       or contributory patent infringement, then any patent licenses | ||||||
|  |       granted to You under this License for that Work shall terminate | ||||||
|  |       as of the date such litigation is filed. | ||||||
|  |  | ||||||
|  |    4. Redistribution. You may reproduce and distribute copies of the | ||||||
|  |       Work or Derivative Works thereof in any medium, with or without | ||||||
|  |       modifications, and in Source or Object form, provided that You | ||||||
|  |       meet the following conditions: | ||||||
|  |  | ||||||
|  |       (a) You must give any other recipients of the Work or | ||||||
|  |           Derivative Works a copy of this License; and | ||||||
|  |  | ||||||
|  |       (b) You must cause any modified files to carry prominent notices | ||||||
|  |           stating that You changed the files; and | ||||||
|  |  | ||||||
|  |       (c) You must retain, in the Source form of any Derivative Works | ||||||
|  |           that You distribute, all copyright, patent, trademark, and | ||||||
|  |           attribution notices from the Source form of the Work, | ||||||
|  |           excluding those notices that do not pertain to any part of | ||||||
|  |           the Derivative Works; and | ||||||
|  |  | ||||||
|  |       (d) If the Work includes a "NOTICE" text file as part of its | ||||||
|  |           distribution, then any Derivative Works that You distribute must | ||||||
|  |           include a readable copy of the attribution notices contained | ||||||
|  |           within such NOTICE file, excluding those notices that do not | ||||||
|  |           pertain to any part of the Derivative Works, in at least one | ||||||
|  |           of the following places: within a NOTICE text file distributed | ||||||
|  |           as part of the Derivative Works; within the Source form or | ||||||
|  |           documentation, if provided along with the Derivative Works; or, | ||||||
|  |           within a display generated by the Derivative Works, if and | ||||||
|  |           wherever such third-party notices normally appear. The contents | ||||||
|  |           of the NOTICE file are for informational purposes only and | ||||||
|  |           do not modify the License. You may add Your own attribution | ||||||
|  |           notices within Derivative Works that You distribute, alongside | ||||||
|  |           or as an addendum to the NOTICE text from the Work, provided | ||||||
|  |           that such additional attribution notices cannot be construed | ||||||
|  |           as modifying the License. | ||||||
|  |  | ||||||
|  |       You may add Your own copyright statement to Your modifications and | ||||||
|  |       may provide additional or different license terms and conditions | ||||||
|  |       for use, reproduction, or distribution of Your modifications, or | ||||||
|  |       for any such Derivative Works as a whole, provided Your use, | ||||||
|  |       reproduction, and distribution of the Work otherwise complies with | ||||||
|  |       the conditions stated in this License. | ||||||
|  |  | ||||||
|  |    5. Submission of Contributions. Unless You explicitly state otherwise, | ||||||
|  |       any Contribution intentionally submitted for inclusion in the Work | ||||||
|  |       by You to the Licensor shall be under the terms and conditions of | ||||||
|  |       this License, without any additional terms or conditions. | ||||||
|  |       Notwithstanding the above, nothing herein shall supersede or modify | ||||||
|  |       the terms of any separate license agreement you may have executed | ||||||
|  |       with Licensor regarding such Contributions. | ||||||
|  |  | ||||||
|  |    6. Trademarks. This License does not grant permission to use the trade | ||||||
|  |       names, trademarks, service marks, or product names of the Licensor, | ||||||
|  |       except as required for reasonable and customary use in describing the | ||||||
|  |       origin of the Work and reproducing the content of the NOTICE file. | ||||||
|  |  | ||||||
|  |    7. Disclaimer of Warranty. Unless required by applicable law or | ||||||
|  |       agreed to in writing, Licensor provides the Work (and each | ||||||
|  |       Contributor provides its Contributions) on an "AS IS" BASIS, | ||||||
|  |       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | ||||||
|  |       implied, including, without limitation, any warranties or conditions | ||||||
|  |       of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A | ||||||
|  |       PARTICULAR PURPOSE. You are solely responsible for determining the | ||||||
|  |       appropriateness of using or redistributing the Work and assume any | ||||||
|  |       risks associated with Your exercise of permissions under this License. | ||||||
|  |  | ||||||
|  |    8. Limitation of Liability. In no event and under no legal theory, | ||||||
|  |       whether in tort (including negligence), contract, or otherwise, | ||||||
|  |       unless required by applicable law (such as deliberate and grossly | ||||||
|  |       negligent acts) or agreed to in writing, shall any Contributor be | ||||||
|  |       liable to You for damages, including any direct, indirect, special, | ||||||
|  |       incidental, or consequential damages of any character arising as a | ||||||
|  |       result of this License or out of the use or inability to use the | ||||||
|  |       Work (including but not limited to damages for loss of goodwill, | ||||||
|  |       work stoppage, computer failure or malfunction, or any and all | ||||||
|  |       other commercial damages or losses), even if such Contributor | ||||||
|  |       has been advised of the possibility of such damages. | ||||||
|  |  | ||||||
|  |    9. Accepting Warranty or Additional Liability. While redistributing | ||||||
|  |       the Work or Derivative Works thereof, You may choose to offer, | ||||||
|  |       and charge a fee for, acceptance of support, warranty, indemnity, | ||||||
|  |       or other liability obligations and/or rights consistent with this | ||||||
|  |       License. However, in accepting such obligations, You may act only | ||||||
|  |       on Your own behalf and on Your sole responsibility, not on behalf | ||||||
|  |       of any other Contributor, and only if You agree to indemnify, | ||||||
|  |       defend, and hold each Contributor harmless for any liability | ||||||
|  |       incurred by, or claims asserted against, such Contributor by reason | ||||||
|  |       of your accepting any such warranty or additional liability. | ||||||
|  |  | ||||||
|  |    END OF TERMS AND CONDITIONS | ||||||
|  |  | ||||||
|  |    APPENDIX: How to apply the Apache License to your work. | ||||||
|  |  | ||||||
|  |       To apply the Apache License to your work, attach the following | ||||||
|  |       boilerplate notice, with the fields enclosed by brackets "{}" | ||||||
|  |       replaced with your own identifying information. (Don't include | ||||||
|  |       the brackets!)  The text should be enclosed in the appropriate | ||||||
|  |       comment syntax for the file format. We also recommend that a | ||||||
|  |       file or class name and description of purpose be included on the | ||||||
|  |       same "printed page" as the copyright notice for easier | ||||||
|  |       identification within third-party archives. | ||||||
|  |  | ||||||
|  |    Copyright {yyyy} {name of copyright owner} | ||||||
|  |  | ||||||
|  |    Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |    you may not use this file except in compliance with the License. | ||||||
|  |    You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |        http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |    Unless required by applicable law or agreed to in writing, software | ||||||
|  |    distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |    See the License for the specific language governing permissions and | ||||||
|  |    limitations under the License. | ||||||
|  |  | ||||||
							
								
								
									
										247
									
								
								vendor/github.com/docker/distribution/digestset/set.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										247
									
								
								vendor/github.com/docker/distribution/digestset/set.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,247 @@ | |||||||
|  | package digestset | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"errors" | ||||||
|  | 	"sort" | ||||||
|  | 	"strings" | ||||||
|  | 	"sync" | ||||||
|  |  | ||||||
|  | 	digest "github.com/opencontainers/go-digest" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | var ( | ||||||
|  | 	// ErrDigestNotFound is used when a matching digest | ||||||
|  | 	// could not be found in a set. | ||||||
|  | 	ErrDigestNotFound = errors.New("digest not found") | ||||||
|  |  | ||||||
|  | 	// ErrDigestAmbiguous is used when multiple digests | ||||||
|  | 	// are found in a set. None of the matching digests | ||||||
|  | 	// should be considered valid matches. | ||||||
|  | 	ErrDigestAmbiguous = errors.New("ambiguous digest string") | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // Set is used to hold a unique set of digests which | ||||||
|  | // may be easily referenced by easily  referenced by a string | ||||||
|  | // representation of the digest as well as short representation. | ||||||
|  | // The uniqueness of the short representation is based on other | ||||||
|  | // digests in the set. If digests are omitted from this set, | ||||||
|  | // collisions in a larger set may not be detected, therefore it | ||||||
|  | // is important to always do short representation lookups on | ||||||
|  | // the complete set of digests. To mitigate collisions, an | ||||||
|  | // appropriately long short code should be used. | ||||||
|  | type Set struct { | ||||||
|  | 	mutex   sync.RWMutex | ||||||
|  | 	entries digestEntries | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // NewSet creates an empty set of digests | ||||||
|  | // which may have digests added. | ||||||
|  | func NewSet() *Set { | ||||||
|  | 	return &Set{ | ||||||
|  | 		entries: digestEntries{}, | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // checkShortMatch checks whether two digests match as either whole | ||||||
|  | // values or short values. This function does not test equality, | ||||||
|  | // rather whether the second value could match against the first | ||||||
|  | // value. | ||||||
|  | func checkShortMatch(alg digest.Algorithm, hex, shortAlg, shortHex string) bool { | ||||||
|  | 	if len(hex) == len(shortHex) { | ||||||
|  | 		if hex != shortHex { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 		if len(shortAlg) > 0 && string(alg) != shortAlg { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 	} else if !strings.HasPrefix(hex, shortHex) { | ||||||
|  | 		return false | ||||||
|  | 	} else if len(shortAlg) > 0 && string(alg) != shortAlg { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	return true | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Lookup looks for a digest matching the given string representation. | ||||||
|  | // If no digests could be found ErrDigestNotFound will be returned | ||||||
|  | // with an empty digest value. If multiple matches are found | ||||||
|  | // ErrDigestAmbiguous will be returned with an empty digest value. | ||||||
|  | func (dst *Set) Lookup(d string) (digest.Digest, error) { | ||||||
|  | 	dst.mutex.RLock() | ||||||
|  | 	defer dst.mutex.RUnlock() | ||||||
|  | 	if len(dst.entries) == 0 { | ||||||
|  | 		return "", ErrDigestNotFound | ||||||
|  | 	} | ||||||
|  | 	var ( | ||||||
|  | 		searchFunc func(int) bool | ||||||
|  | 		alg        digest.Algorithm | ||||||
|  | 		hex        string | ||||||
|  | 	) | ||||||
|  | 	dgst, err := digest.Parse(d) | ||||||
|  | 	if err == digest.ErrDigestInvalidFormat { | ||||||
|  | 		hex = d | ||||||
|  | 		searchFunc = func(i int) bool { | ||||||
|  | 			return dst.entries[i].val >= d | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  | 		hex = dgst.Hex() | ||||||
|  | 		alg = dgst.Algorithm() | ||||||
|  | 		searchFunc = func(i int) bool { | ||||||
|  | 			if dst.entries[i].val == hex { | ||||||
|  | 				return dst.entries[i].alg >= alg | ||||||
|  | 			} | ||||||
|  | 			return dst.entries[i].val >= hex | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	idx := sort.Search(len(dst.entries), searchFunc) | ||||||
|  | 	if idx == len(dst.entries) || !checkShortMatch(dst.entries[idx].alg, dst.entries[idx].val, string(alg), hex) { | ||||||
|  | 		return "", ErrDigestNotFound | ||||||
|  | 	} | ||||||
|  | 	if dst.entries[idx].alg == alg && dst.entries[idx].val == hex { | ||||||
|  | 		return dst.entries[idx].digest, nil | ||||||
|  | 	} | ||||||
|  | 	if idx+1 < len(dst.entries) && checkShortMatch(dst.entries[idx+1].alg, dst.entries[idx+1].val, string(alg), hex) { | ||||||
|  | 		return "", ErrDigestAmbiguous | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return dst.entries[idx].digest, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Add adds the given digest to the set. An error will be returned | ||||||
|  | // if the given digest is invalid. If the digest already exists in the | ||||||
|  | // set, this operation will be a no-op. | ||||||
|  | func (dst *Set) Add(d digest.Digest) error { | ||||||
|  | 	if err := d.Validate(); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	dst.mutex.Lock() | ||||||
|  | 	defer dst.mutex.Unlock() | ||||||
|  | 	entry := &digestEntry{alg: d.Algorithm(), val: d.Hex(), digest: d} | ||||||
|  | 	searchFunc := func(i int) bool { | ||||||
|  | 		if dst.entries[i].val == entry.val { | ||||||
|  | 			return dst.entries[i].alg >= entry.alg | ||||||
|  | 		} | ||||||
|  | 		return dst.entries[i].val >= entry.val | ||||||
|  | 	} | ||||||
|  | 	idx := sort.Search(len(dst.entries), searchFunc) | ||||||
|  | 	if idx == len(dst.entries) { | ||||||
|  | 		dst.entries = append(dst.entries, entry) | ||||||
|  | 		return nil | ||||||
|  | 	} else if dst.entries[idx].digest == d { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	entries := append(dst.entries, nil) | ||||||
|  | 	copy(entries[idx+1:], entries[idx:len(entries)-1]) | ||||||
|  | 	entries[idx] = entry | ||||||
|  | 	dst.entries = entries | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Remove removes the given digest from the set. An err will be | ||||||
|  | // returned if the given digest is invalid. If the digest does | ||||||
|  | // not exist in the set, this operation will be a no-op. | ||||||
|  | func (dst *Set) Remove(d digest.Digest) error { | ||||||
|  | 	if err := d.Validate(); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	dst.mutex.Lock() | ||||||
|  | 	defer dst.mutex.Unlock() | ||||||
|  | 	entry := &digestEntry{alg: d.Algorithm(), val: d.Hex(), digest: d} | ||||||
|  | 	searchFunc := func(i int) bool { | ||||||
|  | 		if dst.entries[i].val == entry.val { | ||||||
|  | 			return dst.entries[i].alg >= entry.alg | ||||||
|  | 		} | ||||||
|  | 		return dst.entries[i].val >= entry.val | ||||||
|  | 	} | ||||||
|  | 	idx := sort.Search(len(dst.entries), searchFunc) | ||||||
|  | 	// Not found if idx is after or value at idx is not digest | ||||||
|  | 	if idx == len(dst.entries) || dst.entries[idx].digest != d { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	entries := dst.entries | ||||||
|  | 	copy(entries[idx:], entries[idx+1:]) | ||||||
|  | 	entries = entries[:len(entries)-1] | ||||||
|  | 	dst.entries = entries | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // All returns all the digests in the set | ||||||
|  | func (dst *Set) All() []digest.Digest { | ||||||
|  | 	dst.mutex.RLock() | ||||||
|  | 	defer dst.mutex.RUnlock() | ||||||
|  | 	retValues := make([]digest.Digest, len(dst.entries)) | ||||||
|  | 	for i := range dst.entries { | ||||||
|  | 		retValues[i] = dst.entries[i].digest | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return retValues | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ShortCodeTable returns a map of Digest to unique short codes. The | ||||||
|  | // length represents the minimum value, the maximum length may be the | ||||||
|  | // entire value of digest if uniqueness cannot be achieved without the | ||||||
|  | // full value. This function will attempt to make short codes as short | ||||||
|  | // as possible to be unique. | ||||||
|  | func ShortCodeTable(dst *Set, length int) map[digest.Digest]string { | ||||||
|  | 	dst.mutex.RLock() | ||||||
|  | 	defer dst.mutex.RUnlock() | ||||||
|  | 	m := make(map[digest.Digest]string, len(dst.entries)) | ||||||
|  | 	l := length | ||||||
|  | 	resetIdx := 0 | ||||||
|  | 	for i := 0; i < len(dst.entries); i++ { | ||||||
|  | 		var short string | ||||||
|  | 		extended := true | ||||||
|  | 		for extended { | ||||||
|  | 			extended = false | ||||||
|  | 			if len(dst.entries[i].val) <= l { | ||||||
|  | 				short = dst.entries[i].digest.String() | ||||||
|  | 			} else { | ||||||
|  | 				short = dst.entries[i].val[:l] | ||||||
|  | 				for j := i + 1; j < len(dst.entries); j++ { | ||||||
|  | 					if checkShortMatch(dst.entries[j].alg, dst.entries[j].val, "", short) { | ||||||
|  | 						if j > resetIdx { | ||||||
|  | 							resetIdx = j | ||||||
|  | 						} | ||||||
|  | 						extended = true | ||||||
|  | 					} else { | ||||||
|  | 						break | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 				if extended { | ||||||
|  | 					l++ | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		m[dst.entries[i].digest] = short | ||||||
|  | 		if i >= resetIdx { | ||||||
|  | 			l = length | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return m | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type digestEntry struct { | ||||||
|  | 	alg    digest.Algorithm | ||||||
|  | 	val    string | ||||||
|  | 	digest digest.Digest | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type digestEntries []*digestEntry | ||||||
|  |  | ||||||
|  | func (d digestEntries) Len() int { | ||||||
|  | 	return len(d) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (d digestEntries) Less(i, j int) bool { | ||||||
|  | 	if d[i].val != d[j].val { | ||||||
|  | 		return d[i].val < d[j].val | ||||||
|  | 	} | ||||||
|  | 	return d[i].alg < d[j].alg | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (d digestEntries) Swap(i, j int) { | ||||||
|  | 	d[i], d[j] = d[j], d[i] | ||||||
|  | } | ||||||
							
								
								
									
										42
									
								
								vendor/github.com/docker/distribution/reference/helpers.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								vendor/github.com/docker/distribution/reference/helpers.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | |||||||
|  | package reference | ||||||
|  |  | ||||||
|  | import "path" | ||||||
|  |  | ||||||
|  | // IsNameOnly returns true if reference only contains a repo name. | ||||||
|  | func IsNameOnly(ref Named) bool { | ||||||
|  | 	if _, ok := ref.(NamedTagged); ok { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	if _, ok := ref.(Canonical); ok { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	return true | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // FamiliarName returns the familiar name string | ||||||
|  | // for the given named, familiarizing if needed. | ||||||
|  | func FamiliarName(ref Named) string { | ||||||
|  | 	if nn, ok := ref.(normalizedNamed); ok { | ||||||
|  | 		return nn.Familiar().Name() | ||||||
|  | 	} | ||||||
|  | 	return ref.Name() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // FamiliarString returns the familiar string representation | ||||||
|  | // for the given reference, familiarizing if needed. | ||||||
|  | func FamiliarString(ref Reference) string { | ||||||
|  | 	if nn, ok := ref.(normalizedNamed); ok { | ||||||
|  | 		return nn.Familiar().String() | ||||||
|  | 	} | ||||||
|  | 	return ref.String() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // FamiliarMatch reports whether ref matches the specified pattern. | ||||||
|  | // See https://godoc.org/path#Match for supported patterns. | ||||||
|  | func FamiliarMatch(pattern string, ref Reference) (bool, error) { | ||||||
|  | 	matched, err := path.Match(pattern, FamiliarString(ref)) | ||||||
|  | 	if namedRef, isNamed := ref.(Named); isNamed && !matched { | ||||||
|  | 		matched, _ = path.Match(pattern, FamiliarName(namedRef)) | ||||||
|  | 	} | ||||||
|  | 	return matched, err | ||||||
|  | } | ||||||
							
								
								
									
										199
									
								
								vendor/github.com/docker/distribution/reference/normalize.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										199
									
								
								vendor/github.com/docker/distribution/reference/normalize.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,199 @@ | |||||||
|  | package reference | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"errors" | ||||||
|  | 	"fmt" | ||||||
|  | 	"strings" | ||||||
|  |  | ||||||
|  | 	"github.com/docker/distribution/digestset" | ||||||
|  | 	"github.com/opencontainers/go-digest" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | var ( | ||||||
|  | 	legacyDefaultDomain = "index.docker.io" | ||||||
|  | 	defaultDomain       = "docker.io" | ||||||
|  | 	officialRepoName    = "library" | ||||||
|  | 	defaultTag          = "latest" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // normalizedNamed represents a name which has been | ||||||
|  | // normalized and has a familiar form. A familiar name | ||||||
|  | // is what is used in Docker UI. An example normalized | ||||||
|  | // name is "docker.io/library/ubuntu" and corresponding | ||||||
|  | // familiar name of "ubuntu". | ||||||
|  | type normalizedNamed interface { | ||||||
|  | 	Named | ||||||
|  | 	Familiar() Named | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ParseNormalizedNamed parses a string into a named reference | ||||||
|  | // transforming a familiar name from Docker UI to a fully | ||||||
|  | // qualified reference. If the value may be an identifier | ||||||
|  | // use ParseAnyReference. | ||||||
|  | func ParseNormalizedNamed(s string) (Named, error) { | ||||||
|  | 	if ok := anchoredIdentifierRegexp.MatchString(s); ok { | ||||||
|  | 		return nil, fmt.Errorf("invalid repository name (%s), cannot specify 64-byte hexadecimal strings", s) | ||||||
|  | 	} | ||||||
|  | 	domain, remainder := splitDockerDomain(s) | ||||||
|  | 	var remoteName string | ||||||
|  | 	if tagSep := strings.IndexRune(remainder, ':'); tagSep > -1 { | ||||||
|  | 		remoteName = remainder[:tagSep] | ||||||
|  | 	} else { | ||||||
|  | 		remoteName = remainder | ||||||
|  | 	} | ||||||
|  | 	if strings.ToLower(remoteName) != remoteName { | ||||||
|  | 		return nil, errors.New("invalid reference format: repository name must be lowercase") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	ref, err := Parse(domain + "/" + remainder) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	named, isNamed := ref.(Named) | ||||||
|  | 	if !isNamed { | ||||||
|  | 		return nil, fmt.Errorf("reference %s has no name", ref.String()) | ||||||
|  | 	} | ||||||
|  | 	return named, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ParseDockerRef normalizes the image reference following the docker convention. This is added | ||||||
|  | // mainly for backward compatibility. | ||||||
|  | // The reference returned can only be either tagged or digested. For reference contains both tag | ||||||
|  | // and digest, the function returns digested reference, e.g. docker.io/library/busybox:latest@ | ||||||
|  | // sha256:7cc4b5aefd1d0cadf8d97d4350462ba51c694ebca145b08d7d41b41acc8db5aa will be returned as | ||||||
|  | // docker.io/library/busybox@sha256:7cc4b5aefd1d0cadf8d97d4350462ba51c694ebca145b08d7d41b41acc8db5aa. | ||||||
|  | func ParseDockerRef(ref string) (Named, error) { | ||||||
|  | 	named, err := ParseNormalizedNamed(ref) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	if _, ok := named.(NamedTagged); ok { | ||||||
|  | 		if canonical, ok := named.(Canonical); ok { | ||||||
|  | 			// The reference is both tagged and digested, only | ||||||
|  | 			// return digested. | ||||||
|  | 			newNamed, err := WithName(canonical.Name()) | ||||||
|  | 			if err != nil { | ||||||
|  | 				return nil, err | ||||||
|  | 			} | ||||||
|  | 			newCanonical, err := WithDigest(newNamed, canonical.Digest()) | ||||||
|  | 			if err != nil { | ||||||
|  | 				return nil, err | ||||||
|  | 			} | ||||||
|  | 			return newCanonical, nil | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return TagNameOnly(named), nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // splitDockerDomain splits a repository name to domain and remotename string. | ||||||
|  | // If no valid domain is found, the default domain is used. Repository name | ||||||
|  | // needs to be already validated before. | ||||||
|  | func splitDockerDomain(name string) (domain, remainder string) { | ||||||
|  | 	i := strings.IndexRune(name, '/') | ||||||
|  | 	if i == -1 || (!strings.ContainsAny(name[:i], ".:") && name[:i] != "localhost") { | ||||||
|  | 		domain, remainder = defaultDomain, name | ||||||
|  | 	} else { | ||||||
|  | 		domain, remainder = name[:i], name[i+1:] | ||||||
|  | 	} | ||||||
|  | 	if domain == legacyDefaultDomain { | ||||||
|  | 		domain = defaultDomain | ||||||
|  | 	} | ||||||
|  | 	if domain == defaultDomain && !strings.ContainsRune(remainder, '/') { | ||||||
|  | 		remainder = officialRepoName + "/" + remainder | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // familiarizeName returns a shortened version of the name familiar | ||||||
|  | // to to the Docker UI. Familiar names have the default domain | ||||||
|  | // "docker.io" and "library/" repository prefix removed. | ||||||
|  | // For example, "docker.io/library/redis" will have the familiar | ||||||
|  | // name "redis" and "docker.io/dmcgowan/myapp" will be "dmcgowan/myapp". | ||||||
|  | // Returns a familiarized named only reference. | ||||||
|  | func familiarizeName(named namedRepository) repository { | ||||||
|  | 	repo := repository{ | ||||||
|  | 		domain: named.Domain(), | ||||||
|  | 		path:   named.Path(), | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if repo.domain == defaultDomain { | ||||||
|  | 		repo.domain = "" | ||||||
|  | 		// Handle official repositories which have the pattern "library/<official repo name>" | ||||||
|  | 		if split := strings.Split(repo.path, "/"); len(split) == 2 && split[0] == officialRepoName { | ||||||
|  | 			repo.path = split[1] | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return repo | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (r reference) Familiar() Named { | ||||||
|  | 	return reference{ | ||||||
|  | 		namedRepository: familiarizeName(r.namedRepository), | ||||||
|  | 		tag:             r.tag, | ||||||
|  | 		digest:          r.digest, | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (r repository) Familiar() Named { | ||||||
|  | 	return familiarizeName(r) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t taggedReference) Familiar() Named { | ||||||
|  | 	return taggedReference{ | ||||||
|  | 		namedRepository: familiarizeName(t.namedRepository), | ||||||
|  | 		tag:             t.tag, | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c canonicalReference) Familiar() Named { | ||||||
|  | 	return canonicalReference{ | ||||||
|  | 		namedRepository: familiarizeName(c.namedRepository), | ||||||
|  | 		digest:          c.digest, | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // TagNameOnly adds the default tag "latest" to a reference if it only has | ||||||
|  | // a repo name. | ||||||
|  | func TagNameOnly(ref Named) Named { | ||||||
|  | 	if IsNameOnly(ref) { | ||||||
|  | 		namedTagged, err := WithTag(ref, defaultTag) | ||||||
|  | 		if err != nil { | ||||||
|  | 			// Default tag must be valid, to create a NamedTagged | ||||||
|  | 			// type with non-validated input the WithTag function | ||||||
|  | 			// should be used instead | ||||||
|  | 			panic(err) | ||||||
|  | 		} | ||||||
|  | 		return namedTagged | ||||||
|  | 	} | ||||||
|  | 	return ref | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ParseAnyReference parses a reference string as a possible identifier, | ||||||
|  | // full digest, or familiar name. | ||||||
|  | func ParseAnyReference(ref string) (Reference, error) { | ||||||
|  | 	if ok := anchoredIdentifierRegexp.MatchString(ref); ok { | ||||||
|  | 		return digestReference("sha256:" + ref), nil | ||||||
|  | 	} | ||||||
|  | 	if dgst, err := digest.Parse(ref); err == nil { | ||||||
|  | 		return digestReference(dgst), nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return ParseNormalizedNamed(ref) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ParseAnyReferenceWithSet parses a reference string as a possible short | ||||||
|  | // identifier to be matched in a digest set, a full digest, or familiar name. | ||||||
|  | func ParseAnyReferenceWithSet(ref string, ds *digestset.Set) (Reference, error) { | ||||||
|  | 	if ok := anchoredShortIdentifierRegexp.MatchString(ref); ok { | ||||||
|  | 		dgst, err := ds.Lookup(ref) | ||||||
|  | 		if err == nil { | ||||||
|  | 			return digestReference(dgst), nil | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  | 		if dgst, err := digest.Parse(ref); err == nil { | ||||||
|  | 			return digestReference(dgst), nil | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return ParseNormalizedNamed(ref) | ||||||
|  | } | ||||||
							
								
								
									
										433
									
								
								vendor/github.com/docker/distribution/reference/reference.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										433
									
								
								vendor/github.com/docker/distribution/reference/reference.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,433 @@ | |||||||
|  | // Package reference provides a general type to represent any way of referencing images within the registry. | ||||||
|  | // Its main purpose is to abstract tags and digests (content-addressable hash). | ||||||
|  | // | ||||||
|  | // Grammar | ||||||
|  | // | ||||||
|  | // 	reference                       := name [ ":" tag ] [ "@" digest ] | ||||||
|  | //	name                            := [domain '/'] path-component ['/' path-component]* | ||||||
|  | //	domain                          := domain-component ['.' domain-component]* [':' port-number] | ||||||
|  | //	domain-component                := /([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])/ | ||||||
|  | //	port-number                     := /[0-9]+/ | ||||||
|  | //	path-component                  := alpha-numeric [separator alpha-numeric]* | ||||||
|  | // 	alpha-numeric                   := /[a-z0-9]+/ | ||||||
|  | //	separator                       := /[_.]|__|[-]*/ | ||||||
|  | // | ||||||
|  | //	tag                             := /[\w][\w.-]{0,127}/ | ||||||
|  | // | ||||||
|  | //	digest                          := digest-algorithm ":" digest-hex | ||||||
|  | //	digest-algorithm                := digest-algorithm-component [ digest-algorithm-separator digest-algorithm-component ]* | ||||||
|  | //	digest-algorithm-separator      := /[+.-_]/ | ||||||
|  | //	digest-algorithm-component      := /[A-Za-z][A-Za-z0-9]*/ | ||||||
|  | //	digest-hex                      := /[0-9a-fA-F]{32,}/ ; At least 128 bit digest value | ||||||
|  | // | ||||||
|  | //	identifier                      := /[a-f0-9]{64}/ | ||||||
|  | //	short-identifier                := /[a-f0-9]{6,64}/ | ||||||
|  | package reference | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"errors" | ||||||
|  | 	"fmt" | ||||||
|  | 	"strings" | ||||||
|  |  | ||||||
|  | 	"github.com/opencontainers/go-digest" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	// NameTotalLengthMax is the maximum total number of characters in a repository name. | ||||||
|  | 	NameTotalLengthMax = 255 | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | var ( | ||||||
|  | 	// ErrReferenceInvalidFormat represents an error while trying to parse a string as a reference. | ||||||
|  | 	ErrReferenceInvalidFormat = errors.New("invalid reference format") | ||||||
|  |  | ||||||
|  | 	// ErrTagInvalidFormat represents an error while trying to parse a string as a tag. | ||||||
|  | 	ErrTagInvalidFormat = errors.New("invalid tag format") | ||||||
|  |  | ||||||
|  | 	// ErrDigestInvalidFormat represents an error while trying to parse a string as a tag. | ||||||
|  | 	ErrDigestInvalidFormat = errors.New("invalid digest format") | ||||||
|  |  | ||||||
|  | 	// ErrNameContainsUppercase is returned for invalid repository names that contain uppercase characters. | ||||||
|  | 	ErrNameContainsUppercase = errors.New("repository name must be lowercase") | ||||||
|  |  | ||||||
|  | 	// ErrNameEmpty is returned for empty, invalid repository names. | ||||||
|  | 	ErrNameEmpty = errors.New("repository name must have at least one component") | ||||||
|  |  | ||||||
|  | 	// ErrNameTooLong is returned when a repository name is longer than NameTotalLengthMax. | ||||||
|  | 	ErrNameTooLong = fmt.Errorf("repository name must not be more than %v characters", NameTotalLengthMax) | ||||||
|  |  | ||||||
|  | 	// ErrNameNotCanonical is returned when a name is not canonical. | ||||||
|  | 	ErrNameNotCanonical = errors.New("repository name must be canonical") | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // Reference is an opaque object reference identifier that may include | ||||||
|  | // modifiers such as a hostname, name, tag, and digest. | ||||||
|  | type Reference interface { | ||||||
|  | 	// String returns the full reference | ||||||
|  | 	String() string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Field provides a wrapper type for resolving correct reference types when | ||||||
|  | // working with encoding. | ||||||
|  | type Field struct { | ||||||
|  | 	reference Reference | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // AsField wraps a reference in a Field for encoding. | ||||||
|  | func AsField(reference Reference) Field { | ||||||
|  | 	return Field{reference} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Reference unwraps the reference type from the field to | ||||||
|  | // return the Reference object. This object should be | ||||||
|  | // of the appropriate type to further check for different | ||||||
|  | // reference types. | ||||||
|  | func (f Field) Reference() Reference { | ||||||
|  | 	return f.reference | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // MarshalText serializes the field to byte text which | ||||||
|  | // is the string of the reference. | ||||||
|  | func (f Field) MarshalText() (p []byte, err error) { | ||||||
|  | 	return []byte(f.reference.String()), nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // UnmarshalText parses text bytes by invoking the | ||||||
|  | // reference parser to ensure the appropriately | ||||||
|  | // typed reference object is wrapped by field. | ||||||
|  | func (f *Field) UnmarshalText(p []byte) error { | ||||||
|  | 	r, err := Parse(string(p)) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	f.reference = r | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Named is an object with a full name | ||||||
|  | type Named interface { | ||||||
|  | 	Reference | ||||||
|  | 	Name() string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Tagged is an object which has a tag | ||||||
|  | type Tagged interface { | ||||||
|  | 	Reference | ||||||
|  | 	Tag() string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // NamedTagged is an object including a name and tag. | ||||||
|  | type NamedTagged interface { | ||||||
|  | 	Named | ||||||
|  | 	Tag() string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Digested is an object which has a digest | ||||||
|  | // in which it can be referenced by | ||||||
|  | type Digested interface { | ||||||
|  | 	Reference | ||||||
|  | 	Digest() digest.Digest | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Canonical reference is an object with a fully unique | ||||||
|  | // name including a name with domain and digest | ||||||
|  | type Canonical interface { | ||||||
|  | 	Named | ||||||
|  | 	Digest() digest.Digest | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // namedRepository is a reference to a repository with a name. | ||||||
|  | // A namedRepository has both domain and path components. | ||||||
|  | type namedRepository interface { | ||||||
|  | 	Named | ||||||
|  | 	Domain() string | ||||||
|  | 	Path() string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Domain returns the domain part of the Named reference | ||||||
|  | func Domain(named Named) string { | ||||||
|  | 	if r, ok := named.(namedRepository); ok { | ||||||
|  | 		return r.Domain() | ||||||
|  | 	} | ||||||
|  | 	domain, _ := splitDomain(named.Name()) | ||||||
|  | 	return domain | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Path returns the name without the domain part of the Named reference | ||||||
|  | func Path(named Named) (name string) { | ||||||
|  | 	if r, ok := named.(namedRepository); ok { | ||||||
|  | 		return r.Path() | ||||||
|  | 	} | ||||||
|  | 	_, path := splitDomain(named.Name()) | ||||||
|  | 	return path | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func splitDomain(name string) (string, string) { | ||||||
|  | 	match := anchoredNameRegexp.FindStringSubmatch(name) | ||||||
|  | 	if len(match) != 3 { | ||||||
|  | 		return "", name | ||||||
|  | 	} | ||||||
|  | 	return match[1], match[2] | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // SplitHostname splits a named reference into a | ||||||
|  | // hostname and name string. If no valid hostname is | ||||||
|  | // found, the hostname is empty and the full value | ||||||
|  | // is returned as name | ||||||
|  | // DEPRECATED: Use Domain or Path | ||||||
|  | func SplitHostname(named Named) (string, string) { | ||||||
|  | 	if r, ok := named.(namedRepository); ok { | ||||||
|  | 		return r.Domain(), r.Path() | ||||||
|  | 	} | ||||||
|  | 	return splitDomain(named.Name()) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Parse parses s and returns a syntactically valid Reference. | ||||||
|  | // If an error was encountered it is returned, along with a nil Reference. | ||||||
|  | // NOTE: Parse will not handle short digests. | ||||||
|  | func Parse(s string) (Reference, error) { | ||||||
|  | 	matches := ReferenceRegexp.FindStringSubmatch(s) | ||||||
|  | 	if matches == nil { | ||||||
|  | 		if s == "" { | ||||||
|  | 			return nil, ErrNameEmpty | ||||||
|  | 		} | ||||||
|  | 		if ReferenceRegexp.FindStringSubmatch(strings.ToLower(s)) != nil { | ||||||
|  | 			return nil, ErrNameContainsUppercase | ||||||
|  | 		} | ||||||
|  | 		return nil, ErrReferenceInvalidFormat | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if len(matches[1]) > NameTotalLengthMax { | ||||||
|  | 		return nil, ErrNameTooLong | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var repo repository | ||||||
|  |  | ||||||
|  | 	nameMatch := anchoredNameRegexp.FindStringSubmatch(matches[1]) | ||||||
|  | 	if len(nameMatch) == 3 { | ||||||
|  | 		repo.domain = nameMatch[1] | ||||||
|  | 		repo.path = nameMatch[2] | ||||||
|  | 	} else { | ||||||
|  | 		repo.domain = "" | ||||||
|  | 		repo.path = matches[1] | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	ref := reference{ | ||||||
|  | 		namedRepository: repo, | ||||||
|  | 		tag:             matches[2], | ||||||
|  | 	} | ||||||
|  | 	if matches[3] != "" { | ||||||
|  | 		var err error | ||||||
|  | 		ref.digest, err = digest.Parse(matches[3]) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	r := getBestReferenceType(ref) | ||||||
|  | 	if r == nil { | ||||||
|  | 		return nil, ErrNameEmpty | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return r, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ParseNamed parses s and returns a syntactically valid reference implementing | ||||||
|  | // the Named interface. The reference must have a name and be in the canonical | ||||||
|  | // form, otherwise an error is returned. | ||||||
|  | // If an error was encountered it is returned, along with a nil Reference. | ||||||
|  | // NOTE: ParseNamed will not handle short digests. | ||||||
|  | func ParseNamed(s string) (Named, error) { | ||||||
|  | 	named, err := ParseNormalizedNamed(s) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	if named.String() != s { | ||||||
|  | 		return nil, ErrNameNotCanonical | ||||||
|  | 	} | ||||||
|  | 	return named, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // WithName returns a named object representing the given string. If the input | ||||||
|  | // is invalid ErrReferenceInvalidFormat will be returned. | ||||||
|  | func WithName(name string) (Named, error) { | ||||||
|  | 	if len(name) > NameTotalLengthMax { | ||||||
|  | 		return nil, ErrNameTooLong | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	match := anchoredNameRegexp.FindStringSubmatch(name) | ||||||
|  | 	if match == nil || len(match) != 3 { | ||||||
|  | 		return nil, ErrReferenceInvalidFormat | ||||||
|  | 	} | ||||||
|  | 	return repository{ | ||||||
|  | 		domain: match[1], | ||||||
|  | 		path:   match[2], | ||||||
|  | 	}, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // WithTag combines the name from "name" and the tag from "tag" to form a | ||||||
|  | // reference incorporating both the name and the tag. | ||||||
|  | func WithTag(name Named, tag string) (NamedTagged, error) { | ||||||
|  | 	if !anchoredTagRegexp.MatchString(tag) { | ||||||
|  | 		return nil, ErrTagInvalidFormat | ||||||
|  | 	} | ||||||
|  | 	var repo repository | ||||||
|  | 	if r, ok := name.(namedRepository); ok { | ||||||
|  | 		repo.domain = r.Domain() | ||||||
|  | 		repo.path = r.Path() | ||||||
|  | 	} else { | ||||||
|  | 		repo.path = name.Name() | ||||||
|  | 	} | ||||||
|  | 	if canonical, ok := name.(Canonical); ok { | ||||||
|  | 		return reference{ | ||||||
|  | 			namedRepository: repo, | ||||||
|  | 			tag:             tag, | ||||||
|  | 			digest:          canonical.Digest(), | ||||||
|  | 		}, nil | ||||||
|  | 	} | ||||||
|  | 	return taggedReference{ | ||||||
|  | 		namedRepository: repo, | ||||||
|  | 		tag:             tag, | ||||||
|  | 	}, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // WithDigest combines the name from "name" and the digest from "digest" to form | ||||||
|  | // a reference incorporating both the name and the digest. | ||||||
|  | func WithDigest(name Named, digest digest.Digest) (Canonical, error) { | ||||||
|  | 	if !anchoredDigestRegexp.MatchString(digest.String()) { | ||||||
|  | 		return nil, ErrDigestInvalidFormat | ||||||
|  | 	} | ||||||
|  | 	var repo repository | ||||||
|  | 	if r, ok := name.(namedRepository); ok { | ||||||
|  | 		repo.domain = r.Domain() | ||||||
|  | 		repo.path = r.Path() | ||||||
|  | 	} else { | ||||||
|  | 		repo.path = name.Name() | ||||||
|  | 	} | ||||||
|  | 	if tagged, ok := name.(Tagged); ok { | ||||||
|  | 		return reference{ | ||||||
|  | 			namedRepository: repo, | ||||||
|  | 			tag:             tagged.Tag(), | ||||||
|  | 			digest:          digest, | ||||||
|  | 		}, nil | ||||||
|  | 	} | ||||||
|  | 	return canonicalReference{ | ||||||
|  | 		namedRepository: repo, | ||||||
|  | 		digest:          digest, | ||||||
|  | 	}, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // TrimNamed removes any tag or digest from the named reference. | ||||||
|  | func TrimNamed(ref Named) Named { | ||||||
|  | 	domain, path := SplitHostname(ref) | ||||||
|  | 	return repository{ | ||||||
|  | 		domain: domain, | ||||||
|  | 		path:   path, | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func getBestReferenceType(ref reference) Reference { | ||||||
|  | 	if ref.Name() == "" { | ||||||
|  | 		// Allow digest only references | ||||||
|  | 		if ref.digest != "" { | ||||||
|  | 			return digestReference(ref.digest) | ||||||
|  | 		} | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 	if ref.tag == "" { | ||||||
|  | 		if ref.digest != "" { | ||||||
|  | 			return canonicalReference{ | ||||||
|  | 				namedRepository: ref.namedRepository, | ||||||
|  | 				digest:          ref.digest, | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		return ref.namedRepository | ||||||
|  | 	} | ||||||
|  | 	if ref.digest == "" { | ||||||
|  | 		return taggedReference{ | ||||||
|  | 			namedRepository: ref.namedRepository, | ||||||
|  | 			tag:             ref.tag, | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return ref | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type reference struct { | ||||||
|  | 	namedRepository | ||||||
|  | 	tag    string | ||||||
|  | 	digest digest.Digest | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (r reference) String() string { | ||||||
|  | 	return r.Name() + ":" + r.tag + "@" + r.digest.String() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (r reference) Tag() string { | ||||||
|  | 	return r.tag | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (r reference) Digest() digest.Digest { | ||||||
|  | 	return r.digest | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type repository struct { | ||||||
|  | 	domain string | ||||||
|  | 	path   string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (r repository) String() string { | ||||||
|  | 	return r.Name() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (r repository) Name() string { | ||||||
|  | 	if r.domain == "" { | ||||||
|  | 		return r.path | ||||||
|  | 	} | ||||||
|  | 	return r.domain + "/" + r.path | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (r repository) Domain() string { | ||||||
|  | 	return r.domain | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (r repository) Path() string { | ||||||
|  | 	return r.path | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type digestReference digest.Digest | ||||||
|  |  | ||||||
|  | func (d digestReference) String() string { | ||||||
|  | 	return digest.Digest(d).String() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (d digestReference) Digest() digest.Digest { | ||||||
|  | 	return digest.Digest(d) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type taggedReference struct { | ||||||
|  | 	namedRepository | ||||||
|  | 	tag string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t taggedReference) String() string { | ||||||
|  | 	return t.Name() + ":" + t.tag | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t taggedReference) Tag() string { | ||||||
|  | 	return t.tag | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type canonicalReference struct { | ||||||
|  | 	namedRepository | ||||||
|  | 	digest digest.Digest | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c canonicalReference) String() string { | ||||||
|  | 	return c.Name() + "@" + c.digest.String() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c canonicalReference) Digest() digest.Digest { | ||||||
|  | 	return c.digest | ||||||
|  | } | ||||||
							
								
								
									
										143
									
								
								vendor/github.com/docker/distribution/reference/regexp.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								vendor/github.com/docker/distribution/reference/regexp.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,143 @@ | |||||||
|  | package reference | ||||||
|  |  | ||||||
|  | import "regexp" | ||||||
|  |  | ||||||
|  | var ( | ||||||
|  | 	// alphaNumericRegexp defines the alpha numeric atom, typically a | ||||||
|  | 	// component of names. This only allows lower case characters and digits. | ||||||
|  | 	alphaNumericRegexp = match(`[a-z0-9]+`) | ||||||
|  |  | ||||||
|  | 	// separatorRegexp defines the separators allowed to be embedded in name | ||||||
|  | 	// components. This allow one period, one or two underscore and multiple | ||||||
|  | 	// dashes. | ||||||
|  | 	separatorRegexp = match(`(?:[._]|__|[-]*)`) | ||||||
|  |  | ||||||
|  | 	// nameComponentRegexp restricts registry path component names to start | ||||||
|  | 	// with at least one letter or number, with following parts able to be | ||||||
|  | 	// separated by one period, one or two underscore and multiple dashes. | ||||||
|  | 	nameComponentRegexp = expression( | ||||||
|  | 		alphaNumericRegexp, | ||||||
|  | 		optional(repeated(separatorRegexp, alphaNumericRegexp))) | ||||||
|  |  | ||||||
|  | 	// domainComponentRegexp restricts the registry domain component of a | ||||||
|  | 	// repository name to start with a component as defined by DomainRegexp | ||||||
|  | 	// and followed by an optional port. | ||||||
|  | 	domainComponentRegexp = match(`(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])`) | ||||||
|  |  | ||||||
|  | 	// DomainRegexp defines the structure of potential domain components | ||||||
|  | 	// that may be part of image names. This is purposely a subset of what is | ||||||
|  | 	// allowed by DNS to ensure backwards compatibility with Docker image | ||||||
|  | 	// names. | ||||||
|  | 	DomainRegexp = expression( | ||||||
|  | 		domainComponentRegexp, | ||||||
|  | 		optional(repeated(literal(`.`), domainComponentRegexp)), | ||||||
|  | 		optional(literal(`:`), match(`[0-9]+`))) | ||||||
|  |  | ||||||
|  | 	// TagRegexp matches valid tag names. From docker/docker:graph/tags.go. | ||||||
|  | 	TagRegexp = match(`[\w][\w.-]{0,127}`) | ||||||
|  |  | ||||||
|  | 	// anchoredTagRegexp matches valid tag names, anchored at the start and | ||||||
|  | 	// end of the matched string. | ||||||
|  | 	anchoredTagRegexp = anchored(TagRegexp) | ||||||
|  |  | ||||||
|  | 	// DigestRegexp matches valid digests. | ||||||
|  | 	DigestRegexp = match(`[A-Za-z][A-Za-z0-9]*(?:[-_+.][A-Za-z][A-Za-z0-9]*)*[:][[:xdigit:]]{32,}`) | ||||||
|  |  | ||||||
|  | 	// anchoredDigestRegexp matches valid digests, anchored at the start and | ||||||
|  | 	// end of the matched string. | ||||||
|  | 	anchoredDigestRegexp = anchored(DigestRegexp) | ||||||
|  |  | ||||||
|  | 	// NameRegexp is the format for the name component of references. The | ||||||
|  | 	// regexp has capturing groups for the domain and name part omitting | ||||||
|  | 	// the separating forward slash from either. | ||||||
|  | 	NameRegexp = expression( | ||||||
|  | 		optional(DomainRegexp, literal(`/`)), | ||||||
|  | 		nameComponentRegexp, | ||||||
|  | 		optional(repeated(literal(`/`), nameComponentRegexp))) | ||||||
|  |  | ||||||
|  | 	// anchoredNameRegexp is used to parse a name value, capturing the | ||||||
|  | 	// domain and trailing components. | ||||||
|  | 	anchoredNameRegexp = anchored( | ||||||
|  | 		optional(capture(DomainRegexp), literal(`/`)), | ||||||
|  | 		capture(nameComponentRegexp, | ||||||
|  | 			optional(repeated(literal(`/`), nameComponentRegexp)))) | ||||||
|  |  | ||||||
|  | 	// ReferenceRegexp is the full supported format of a reference. The regexp | ||||||
|  | 	// is anchored and has capturing groups for name, tag, and digest | ||||||
|  | 	// components. | ||||||
|  | 	ReferenceRegexp = anchored(capture(NameRegexp), | ||||||
|  | 		optional(literal(":"), capture(TagRegexp)), | ||||||
|  | 		optional(literal("@"), capture(DigestRegexp))) | ||||||
|  |  | ||||||
|  | 	// IdentifierRegexp is the format for string identifier used as a | ||||||
|  | 	// content addressable identifier using sha256. These identifiers | ||||||
|  | 	// are like digests without the algorithm, since sha256 is used. | ||||||
|  | 	IdentifierRegexp = match(`([a-f0-9]{64})`) | ||||||
|  |  | ||||||
|  | 	// ShortIdentifierRegexp is the format used to represent a prefix | ||||||
|  | 	// of an identifier. A prefix may be used to match a sha256 identifier | ||||||
|  | 	// within a list of trusted identifiers. | ||||||
|  | 	ShortIdentifierRegexp = match(`([a-f0-9]{6,64})`) | ||||||
|  |  | ||||||
|  | 	// anchoredIdentifierRegexp is used to check or match an | ||||||
|  | 	// identifier value, anchored at start and end of string. | ||||||
|  | 	anchoredIdentifierRegexp = anchored(IdentifierRegexp) | ||||||
|  |  | ||||||
|  | 	// anchoredShortIdentifierRegexp is used to check if a value | ||||||
|  | 	// is a possible identifier prefix, anchored at start and end | ||||||
|  | 	// of string. | ||||||
|  | 	anchoredShortIdentifierRegexp = anchored(ShortIdentifierRegexp) | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // match compiles the string to a regular expression. | ||||||
|  | var match = regexp.MustCompile | ||||||
|  |  | ||||||
|  | // literal compiles s into a literal regular expression, escaping any regexp | ||||||
|  | // reserved characters. | ||||||
|  | func literal(s string) *regexp.Regexp { | ||||||
|  | 	re := match(regexp.QuoteMeta(s)) | ||||||
|  |  | ||||||
|  | 	if _, complete := re.LiteralPrefix(); !complete { | ||||||
|  | 		panic("must be a literal") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return re | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // expression defines a full expression, where each regular expression must | ||||||
|  | // follow the previous. | ||||||
|  | func expression(res ...*regexp.Regexp) *regexp.Regexp { | ||||||
|  | 	var s string | ||||||
|  | 	for _, re := range res { | ||||||
|  | 		s += re.String() | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return match(s) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // optional wraps the expression in a non-capturing group and makes the | ||||||
|  | // production optional. | ||||||
|  | func optional(res ...*regexp.Regexp) *regexp.Regexp { | ||||||
|  | 	return match(group(expression(res...)).String() + `?`) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // repeated wraps the regexp in a non-capturing group to get one or more | ||||||
|  | // matches. | ||||||
|  | func repeated(res ...*regexp.Regexp) *regexp.Regexp { | ||||||
|  | 	return match(group(expression(res...)).String() + `+`) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // group wraps the regexp in a non-capturing group. | ||||||
|  | func group(res ...*regexp.Regexp) *regexp.Regexp { | ||||||
|  | 	return match(`(?:` + expression(res...).String() + `)`) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // capture wraps the expression in a capturing group. | ||||||
|  | func capture(res ...*regexp.Regexp) *regexp.Regexp { | ||||||
|  | 	return match(`(` + expression(res...).String() + `)`) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // anchored anchors the regular expression by adding start and end delimiters. | ||||||
|  | func anchored(res ...*regexp.Regexp) *regexp.Regexp { | ||||||
|  | 	return match(`^` + expression(res...).String() + `$`) | ||||||
|  | } | ||||||
							
								
								
									
										267
									
								
								vendor/github.com/docker/distribution/registry/api/errcode/errors.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										267
									
								
								vendor/github.com/docker/distribution/registry/api/errcode/errors.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,267 @@ | |||||||
|  | package errcode | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"encoding/json" | ||||||
|  | 	"fmt" | ||||||
|  | 	"strings" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // ErrorCoder is the base interface for ErrorCode and Error allowing | ||||||
|  | // users of each to just call ErrorCode to get the real ID of each | ||||||
|  | type ErrorCoder interface { | ||||||
|  | 	ErrorCode() ErrorCode | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ErrorCode represents the error type. The errors are serialized via strings | ||||||
|  | // and the integer format may change and should *never* be exported. | ||||||
|  | type ErrorCode int | ||||||
|  |  | ||||||
|  | var _ error = ErrorCode(0) | ||||||
|  |  | ||||||
|  | // ErrorCode just returns itself | ||||||
|  | func (ec ErrorCode) ErrorCode() ErrorCode { | ||||||
|  | 	return ec | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Error returns the ID/Value | ||||||
|  | func (ec ErrorCode) Error() string { | ||||||
|  | 	// NOTE(stevvooe): Cannot use message here since it may have unpopulated args. | ||||||
|  | 	return strings.ToLower(strings.Replace(ec.String(), "_", " ", -1)) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Descriptor returns the descriptor for the error code. | ||||||
|  | func (ec ErrorCode) Descriptor() ErrorDescriptor { | ||||||
|  | 	d, ok := errorCodeToDescriptors[ec] | ||||||
|  |  | ||||||
|  | 	if !ok { | ||||||
|  | 		return ErrorCodeUnknown.Descriptor() | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return d | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // String returns the canonical identifier for this error code. | ||||||
|  | func (ec ErrorCode) String() string { | ||||||
|  | 	return ec.Descriptor().Value | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Message returned the human-readable error message for this error code. | ||||||
|  | func (ec ErrorCode) Message() string { | ||||||
|  | 	return ec.Descriptor().Message | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // MarshalText encodes the receiver into UTF-8-encoded text and returns the | ||||||
|  | // result. | ||||||
|  | func (ec ErrorCode) MarshalText() (text []byte, err error) { | ||||||
|  | 	return []byte(ec.String()), nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // UnmarshalText decodes the form generated by MarshalText. | ||||||
|  | func (ec *ErrorCode) UnmarshalText(text []byte) error { | ||||||
|  | 	desc, ok := idToDescriptors[string(text)] | ||||||
|  |  | ||||||
|  | 	if !ok { | ||||||
|  | 		desc = ErrorCodeUnknown.Descriptor() | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	*ec = desc.Code | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // WithMessage creates a new Error struct based on the passed-in info and | ||||||
|  | // overrides the Message property. | ||||||
|  | func (ec ErrorCode) WithMessage(message string) Error { | ||||||
|  | 	return Error{ | ||||||
|  | 		Code:    ec, | ||||||
|  | 		Message: message, | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // WithDetail creates a new Error struct based on the passed-in info and | ||||||
|  | // set the Detail property appropriately | ||||||
|  | func (ec ErrorCode) WithDetail(detail interface{}) Error { | ||||||
|  | 	return Error{ | ||||||
|  | 		Code:    ec, | ||||||
|  | 		Message: ec.Message(), | ||||||
|  | 	}.WithDetail(detail) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // WithArgs creates a new Error struct and sets the Args slice | ||||||
|  | func (ec ErrorCode) WithArgs(args ...interface{}) Error { | ||||||
|  | 	return Error{ | ||||||
|  | 		Code:    ec, | ||||||
|  | 		Message: ec.Message(), | ||||||
|  | 	}.WithArgs(args...) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Error provides a wrapper around ErrorCode with extra Details provided. | ||||||
|  | type Error struct { | ||||||
|  | 	Code    ErrorCode   `json:"code"` | ||||||
|  | 	Message string      `json:"message"` | ||||||
|  | 	Detail  interface{} `json:"detail,omitempty"` | ||||||
|  |  | ||||||
|  | 	// TODO(duglin): See if we need an "args" property so we can do the | ||||||
|  | 	// variable substitution right before showing the message to the user | ||||||
|  | } | ||||||
|  |  | ||||||
|  | var _ error = Error{} | ||||||
|  |  | ||||||
|  | // ErrorCode returns the ID/Value of this Error | ||||||
|  | func (e Error) ErrorCode() ErrorCode { | ||||||
|  | 	return e.Code | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Error returns a human readable representation of the error. | ||||||
|  | func (e Error) Error() string { | ||||||
|  | 	return fmt.Sprintf("%s: %s", e.Code.Error(), e.Message) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // WithDetail will return a new Error, based on the current one, but with | ||||||
|  | // some Detail info added | ||||||
|  | func (e Error) WithDetail(detail interface{}) Error { | ||||||
|  | 	return Error{ | ||||||
|  | 		Code:    e.Code, | ||||||
|  | 		Message: e.Message, | ||||||
|  | 		Detail:  detail, | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // WithArgs uses the passed-in list of interface{} as the substitution | ||||||
|  | // variables in the Error's Message string, but returns a new Error | ||||||
|  | func (e Error) WithArgs(args ...interface{}) Error { | ||||||
|  | 	return Error{ | ||||||
|  | 		Code:    e.Code, | ||||||
|  | 		Message: fmt.Sprintf(e.Code.Message(), args...), | ||||||
|  | 		Detail:  e.Detail, | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ErrorDescriptor provides relevant information about a given error code. | ||||||
|  | type ErrorDescriptor struct { | ||||||
|  | 	// Code is the error code that this descriptor describes. | ||||||
|  | 	Code ErrorCode | ||||||
|  |  | ||||||
|  | 	// Value provides a unique, string key, often captilized with | ||||||
|  | 	// underscores, to identify the error code. This value is used as the | ||||||
|  | 	// keyed value when serializing api errors. | ||||||
|  | 	Value string | ||||||
|  |  | ||||||
|  | 	// Message is a short, human readable decription of the error condition | ||||||
|  | 	// included in API responses. | ||||||
|  | 	Message string | ||||||
|  |  | ||||||
|  | 	// Description provides a complete account of the errors purpose, suitable | ||||||
|  | 	// for use in documentation. | ||||||
|  | 	Description string | ||||||
|  |  | ||||||
|  | 	// HTTPStatusCode provides the http status code that is associated with | ||||||
|  | 	// this error condition. | ||||||
|  | 	HTTPStatusCode int | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ParseErrorCode returns the value by the string error code. | ||||||
|  | // `ErrorCodeUnknown` will be returned if the error is not known. | ||||||
|  | func ParseErrorCode(value string) ErrorCode { | ||||||
|  | 	ed, ok := idToDescriptors[value] | ||||||
|  | 	if ok { | ||||||
|  | 		return ed.Code | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return ErrorCodeUnknown | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Errors provides the envelope for multiple errors and a few sugar methods | ||||||
|  | // for use within the application. | ||||||
|  | type Errors []error | ||||||
|  |  | ||||||
|  | var _ error = Errors{} | ||||||
|  |  | ||||||
|  | func (errs Errors) Error() string { | ||||||
|  | 	switch len(errs) { | ||||||
|  | 	case 0: | ||||||
|  | 		return "<nil>" | ||||||
|  | 	case 1: | ||||||
|  | 		return errs[0].Error() | ||||||
|  | 	default: | ||||||
|  | 		msg := "errors:\n" | ||||||
|  | 		for _, err := range errs { | ||||||
|  | 			msg += err.Error() + "\n" | ||||||
|  | 		} | ||||||
|  | 		return msg | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Len returns the current number of errors. | ||||||
|  | func (errs Errors) Len() int { | ||||||
|  | 	return len(errs) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // MarshalJSON converts slice of error, ErrorCode or Error into a | ||||||
|  | // slice of Error - then serializes | ||||||
|  | func (errs Errors) MarshalJSON() ([]byte, error) { | ||||||
|  | 	var tmpErrs struct { | ||||||
|  | 		Errors []Error `json:"errors,omitempty"` | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	for _, daErr := range errs { | ||||||
|  | 		var err Error | ||||||
|  |  | ||||||
|  | 		switch daErr := daErr.(type) { | ||||||
|  | 		case ErrorCode: | ||||||
|  | 			err = daErr.WithDetail(nil) | ||||||
|  | 		case Error: | ||||||
|  | 			err = daErr | ||||||
|  | 		default: | ||||||
|  | 			err = ErrorCodeUnknown.WithDetail(daErr) | ||||||
|  |  | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// If the Error struct was setup and they forgot to set the | ||||||
|  | 		// Message field (meaning its "") then grab it from the ErrCode | ||||||
|  | 		msg := err.Message | ||||||
|  | 		if msg == "" { | ||||||
|  | 			msg = err.Code.Message() | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		tmpErrs.Errors = append(tmpErrs.Errors, Error{ | ||||||
|  | 			Code:    err.Code, | ||||||
|  | 			Message: msg, | ||||||
|  | 			Detail:  err.Detail, | ||||||
|  | 		}) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return json.Marshal(tmpErrs) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // UnmarshalJSON deserializes []Error and then converts it into slice of | ||||||
|  | // Error or ErrorCode | ||||||
|  | func (errs *Errors) UnmarshalJSON(data []byte) error { | ||||||
|  | 	var tmpErrs struct { | ||||||
|  | 		Errors []Error | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if err := json.Unmarshal(data, &tmpErrs); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var newErrs Errors | ||||||
|  | 	for _, daErr := range tmpErrs.Errors { | ||||||
|  | 		// If Message is empty or exactly matches the Code's message string | ||||||
|  | 		// then just use the Code, no need for a full Error struct | ||||||
|  | 		if daErr.Detail == nil && (daErr.Message == "" || daErr.Message == daErr.Code.Message()) { | ||||||
|  | 			// Error's w/o details get converted to ErrorCode | ||||||
|  | 			newErrs = append(newErrs, daErr.Code) | ||||||
|  | 		} else { | ||||||
|  | 			// Error's w/ details are untouched | ||||||
|  | 			newErrs = append(newErrs, Error{ | ||||||
|  | 				Code:    daErr.Code, | ||||||
|  | 				Message: daErr.Message, | ||||||
|  | 				Detail:  daErr.Detail, | ||||||
|  | 			}) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	*errs = newErrs | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
							
								
								
									
										40
									
								
								vendor/github.com/docker/distribution/registry/api/errcode/handler.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								vendor/github.com/docker/distribution/registry/api/errcode/handler.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | |||||||
|  | package errcode | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"encoding/json" | ||||||
|  | 	"net/http" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // ServeJSON attempts to serve the errcode in a JSON envelope. It marshals err | ||||||
|  | // and sets the content-type header to 'application/json'. It will handle | ||||||
|  | // ErrorCoder and Errors, and if necessary will create an envelope. | ||||||
|  | func ServeJSON(w http.ResponseWriter, err error) error { | ||||||
|  | 	w.Header().Set("Content-Type", "application/json; charset=utf-8") | ||||||
|  | 	var sc int | ||||||
|  |  | ||||||
|  | 	switch errs := err.(type) { | ||||||
|  | 	case Errors: | ||||||
|  | 		if len(errs) < 1 { | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if err, ok := errs[0].(ErrorCoder); ok { | ||||||
|  | 			sc = err.ErrorCode().Descriptor().HTTPStatusCode | ||||||
|  | 		} | ||||||
|  | 	case ErrorCoder: | ||||||
|  | 		sc = errs.ErrorCode().Descriptor().HTTPStatusCode | ||||||
|  | 		err = Errors{err} // create an envelope. | ||||||
|  | 	default: | ||||||
|  | 		// We just have an unhandled error type, so just place in an envelope | ||||||
|  | 		// and move along. | ||||||
|  | 		err = Errors{err} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if sc == 0 { | ||||||
|  | 		sc = http.StatusInternalServerError | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	w.WriteHeader(sc) | ||||||
|  |  | ||||||
|  | 	return json.NewEncoder(w).Encode(err) | ||||||
|  | } | ||||||
							
								
								
									
										138
									
								
								vendor/github.com/docker/distribution/registry/api/errcode/register.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										138
									
								
								vendor/github.com/docker/distribution/registry/api/errcode/register.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,138 @@ | |||||||
|  | package errcode | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"net/http" | ||||||
|  | 	"sort" | ||||||
|  | 	"sync" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | var ( | ||||||
|  | 	errorCodeToDescriptors = map[ErrorCode]ErrorDescriptor{} | ||||||
|  | 	idToDescriptors        = map[string]ErrorDescriptor{} | ||||||
|  | 	groupToDescriptors     = map[string][]ErrorDescriptor{} | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | var ( | ||||||
|  | 	// ErrorCodeUnknown is a generic error that can be used as a last | ||||||
|  | 	// resort if there is no situation-specific error message that can be used | ||||||
|  | 	ErrorCodeUnknown = Register("errcode", ErrorDescriptor{ | ||||||
|  | 		Value:   "UNKNOWN", | ||||||
|  | 		Message: "unknown error", | ||||||
|  | 		Description: `Generic error returned when the error does not have an | ||||||
|  | 			                                            API classification.`, | ||||||
|  | 		HTTPStatusCode: http.StatusInternalServerError, | ||||||
|  | 	}) | ||||||
|  |  | ||||||
|  | 	// ErrorCodeUnsupported is returned when an operation is not supported. | ||||||
|  | 	ErrorCodeUnsupported = Register("errcode", ErrorDescriptor{ | ||||||
|  | 		Value:   "UNSUPPORTED", | ||||||
|  | 		Message: "The operation is unsupported.", | ||||||
|  | 		Description: `The operation was unsupported due to a missing | ||||||
|  | 		implementation or invalid set of parameters.`, | ||||||
|  | 		HTTPStatusCode: http.StatusMethodNotAllowed, | ||||||
|  | 	}) | ||||||
|  |  | ||||||
|  | 	// ErrorCodeUnauthorized is returned if a request requires | ||||||
|  | 	// authentication. | ||||||
|  | 	ErrorCodeUnauthorized = Register("errcode", ErrorDescriptor{ | ||||||
|  | 		Value:   "UNAUTHORIZED", | ||||||
|  | 		Message: "authentication required", | ||||||
|  | 		Description: `The access controller was unable to authenticate | ||||||
|  | 		the client. Often this will be accompanied by a | ||||||
|  | 		Www-Authenticate HTTP response header indicating how to | ||||||
|  | 		authenticate.`, | ||||||
|  | 		HTTPStatusCode: http.StatusUnauthorized, | ||||||
|  | 	}) | ||||||
|  |  | ||||||
|  | 	// ErrorCodeDenied is returned if a client does not have sufficient | ||||||
|  | 	// permission to perform an action. | ||||||
|  | 	ErrorCodeDenied = Register("errcode", ErrorDescriptor{ | ||||||
|  | 		Value:   "DENIED", | ||||||
|  | 		Message: "requested access to the resource is denied", | ||||||
|  | 		Description: `The access controller denied access for the | ||||||
|  | 		operation on a resource.`, | ||||||
|  | 		HTTPStatusCode: http.StatusForbidden, | ||||||
|  | 	}) | ||||||
|  |  | ||||||
|  | 	// ErrorCodeUnavailable provides a common error to report unavailability | ||||||
|  | 	// of a service or endpoint. | ||||||
|  | 	ErrorCodeUnavailable = Register("errcode", ErrorDescriptor{ | ||||||
|  | 		Value:          "UNAVAILABLE", | ||||||
|  | 		Message:        "service unavailable", | ||||||
|  | 		Description:    "Returned when a service is not available", | ||||||
|  | 		HTTPStatusCode: http.StatusServiceUnavailable, | ||||||
|  | 	}) | ||||||
|  |  | ||||||
|  | 	// ErrorCodeTooManyRequests is returned if a client attempts too many | ||||||
|  | 	// times to contact a service endpoint. | ||||||
|  | 	ErrorCodeTooManyRequests = Register("errcode", ErrorDescriptor{ | ||||||
|  | 		Value:   "TOOMANYREQUESTS", | ||||||
|  | 		Message: "too many requests", | ||||||
|  | 		Description: `Returned when a client attempts to contact a | ||||||
|  | 		service too many times`, | ||||||
|  | 		HTTPStatusCode: http.StatusTooManyRequests, | ||||||
|  | 	}) | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | var nextCode = 1000 | ||||||
|  | var registerLock sync.Mutex | ||||||
|  |  | ||||||
|  | // Register will make the passed-in error known to the environment and | ||||||
|  | // return a new ErrorCode | ||||||
|  | func Register(group string, descriptor ErrorDescriptor) ErrorCode { | ||||||
|  | 	registerLock.Lock() | ||||||
|  | 	defer registerLock.Unlock() | ||||||
|  |  | ||||||
|  | 	descriptor.Code = ErrorCode(nextCode) | ||||||
|  |  | ||||||
|  | 	if _, ok := idToDescriptors[descriptor.Value]; ok { | ||||||
|  | 		panic(fmt.Sprintf("ErrorValue %q is already registered", descriptor.Value)) | ||||||
|  | 	} | ||||||
|  | 	if _, ok := errorCodeToDescriptors[descriptor.Code]; ok { | ||||||
|  | 		panic(fmt.Sprintf("ErrorCode %v is already registered", descriptor.Code)) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	groupToDescriptors[group] = append(groupToDescriptors[group], descriptor) | ||||||
|  | 	errorCodeToDescriptors[descriptor.Code] = descriptor | ||||||
|  | 	idToDescriptors[descriptor.Value] = descriptor | ||||||
|  |  | ||||||
|  | 	nextCode++ | ||||||
|  | 	return descriptor.Code | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type byValue []ErrorDescriptor | ||||||
|  |  | ||||||
|  | func (a byValue) Len() int           { return len(a) } | ||||||
|  | func (a byValue) Swap(i, j int)      { a[i], a[j] = a[j], a[i] } | ||||||
|  | func (a byValue) Less(i, j int) bool { return a[i].Value < a[j].Value } | ||||||
|  |  | ||||||
|  | // GetGroupNames returns the list of Error group names that are registered | ||||||
|  | func GetGroupNames() []string { | ||||||
|  | 	keys := []string{} | ||||||
|  |  | ||||||
|  | 	for k := range groupToDescriptors { | ||||||
|  | 		keys = append(keys, k) | ||||||
|  | 	} | ||||||
|  | 	sort.Strings(keys) | ||||||
|  | 	return keys | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // GetErrorCodeGroup returns the named group of error descriptors | ||||||
|  | func GetErrorCodeGroup(name string) []ErrorDescriptor { | ||||||
|  | 	desc := groupToDescriptors[name] | ||||||
|  | 	sort.Sort(byValue(desc)) | ||||||
|  | 	return desc | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // GetErrorAllDescriptors returns a slice of all ErrorDescriptors that are | ||||||
|  | // registered, irrespective of what group they're in | ||||||
|  | func GetErrorAllDescriptors() []ErrorDescriptor { | ||||||
|  | 	result := []ErrorDescriptor{} | ||||||
|  |  | ||||||
|  | 	for _, group := range GetGroupNames() { | ||||||
|  | 		result = append(result, GetErrorCodeGroup(group)...) | ||||||
|  | 	} | ||||||
|  | 	sort.Sort(byValue(result)) | ||||||
|  | 	return result | ||||||
|  | } | ||||||
							
								
								
									
										2082
									
								
								vendor/github.com/docker/docker/AUTHORS
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2082
									
								
								vendor/github.com/docker/docker/AUTHORS
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										191
									
								
								vendor/github.com/docker/docker/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										191
									
								
								vendor/github.com/docker/docker/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,191 @@ | |||||||
|  |  | ||||||
|  |                                  Apache License | ||||||
|  |                            Version 2.0, January 2004 | ||||||
|  |                         https://www.apache.org/licenses/ | ||||||
|  |  | ||||||
|  |    TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION | ||||||
|  |  | ||||||
|  |    1. Definitions. | ||||||
|  |  | ||||||
|  |       "License" shall mean the terms and conditions for use, reproduction, | ||||||
|  |       and distribution as defined by Sections 1 through 9 of this document. | ||||||
|  |  | ||||||
|  |       "Licensor" shall mean the copyright owner or entity authorized by | ||||||
|  |       the copyright owner that is granting the License. | ||||||
|  |  | ||||||
|  |       "Legal Entity" shall mean the union of the acting entity and all | ||||||
|  |       other entities that control, are controlled by, or are under common | ||||||
|  |       control with that entity. For the purposes of this definition, | ||||||
|  |       "control" means (i) the power, direct or indirect, to cause the | ||||||
|  |       direction or management of such entity, whether by contract or | ||||||
|  |       otherwise, or (ii) ownership of fifty percent (50%) or more of the | ||||||
|  |       outstanding shares, or (iii) beneficial ownership of such entity. | ||||||
|  |  | ||||||
|  |       "You" (or "Your") shall mean an individual or Legal Entity | ||||||
|  |       exercising permissions granted by this License. | ||||||
|  |  | ||||||
|  |       "Source" form shall mean the preferred form for making modifications, | ||||||
|  |       including but not limited to software source code, documentation | ||||||
|  |       source, and configuration files. | ||||||
|  |  | ||||||
|  |       "Object" form shall mean any form resulting from mechanical | ||||||
|  |       transformation or translation of a Source form, including but | ||||||
|  |       not limited to compiled object code, generated documentation, | ||||||
|  |       and conversions to other media types. | ||||||
|  |  | ||||||
|  |       "Work" shall mean the work of authorship, whether in Source or | ||||||
|  |       Object form, made available under the License, as indicated by a | ||||||
|  |       copyright notice that is included in or attached to the work | ||||||
|  |       (an example is provided in the Appendix below). | ||||||
|  |  | ||||||
|  |       "Derivative Works" shall mean any work, whether in Source or Object | ||||||
|  |       form, that is based on (or derived from) the Work and for which the | ||||||
|  |       editorial revisions, annotations, elaborations, or other modifications | ||||||
|  |       represent, as a whole, an original work of authorship. For the purposes | ||||||
|  |       of this License, Derivative Works shall not include works that remain | ||||||
|  |       separable from, or merely link (or bind by name) to the interfaces of, | ||||||
|  |       the Work and Derivative Works thereof. | ||||||
|  |  | ||||||
|  |       "Contribution" shall mean any work of authorship, including | ||||||
|  |       the original version of the Work and any modifications or additions | ||||||
|  |       to that Work or Derivative Works thereof, that is intentionally | ||||||
|  |       submitted to Licensor for inclusion in the Work by the copyright owner | ||||||
|  |       or by an individual or Legal Entity authorized to submit on behalf of | ||||||
|  |       the copyright owner. For the purposes of this definition, "submitted" | ||||||
|  |       means any form of electronic, verbal, or written communication sent | ||||||
|  |       to the Licensor or its representatives, including but not limited to | ||||||
|  |       communication on electronic mailing lists, source code control systems, | ||||||
|  |       and issue tracking systems that are managed by, or on behalf of, the | ||||||
|  |       Licensor for the purpose of discussing and improving the Work, but | ||||||
|  |       excluding communication that is conspicuously marked or otherwise | ||||||
|  |       designated in writing by the copyright owner as "Not a Contribution." | ||||||
|  |  | ||||||
|  |       "Contributor" shall mean Licensor and any individual or Legal Entity | ||||||
|  |       on behalf of whom a Contribution has been received by Licensor and | ||||||
|  |       subsequently incorporated within the Work. | ||||||
|  |  | ||||||
|  |    2. Grant of Copyright License. Subject to the terms and conditions of | ||||||
|  |       this License, each Contributor hereby grants to You a perpetual, | ||||||
|  |       worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||||||
|  |       copyright license to reproduce, prepare Derivative Works of, | ||||||
|  |       publicly display, publicly perform, sublicense, and distribute the | ||||||
|  |       Work and such Derivative Works in Source or Object form. | ||||||
|  |  | ||||||
|  |    3. Grant of Patent License. Subject to the terms and conditions of | ||||||
|  |       this License, each Contributor hereby grants to You a perpetual, | ||||||
|  |       worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||||||
|  |       (except as stated in this section) patent license to make, have made, | ||||||
|  |       use, offer to sell, sell, import, and otherwise transfer the Work, | ||||||
|  |       where such license applies only to those patent claims licensable | ||||||
|  |       by such Contributor that are necessarily infringed by their | ||||||
|  |       Contribution(s) alone or by combination of their Contribution(s) | ||||||
|  |       with the Work to which such Contribution(s) was submitted. If You | ||||||
|  |       institute patent litigation against any entity (including a | ||||||
|  |       cross-claim or counterclaim in a lawsuit) alleging that the Work | ||||||
|  |       or a Contribution incorporated within the Work constitutes direct | ||||||
|  |       or contributory patent infringement, then any patent licenses | ||||||
|  |       granted to You under this License for that Work shall terminate | ||||||
|  |       as of the date such litigation is filed. | ||||||
|  |  | ||||||
|  |    4. Redistribution. You may reproduce and distribute copies of the | ||||||
|  |       Work or Derivative Works thereof in any medium, with or without | ||||||
|  |       modifications, and in Source or Object form, provided that You | ||||||
|  |       meet the following conditions: | ||||||
|  |  | ||||||
|  |       (a) You must give any other recipients of the Work or | ||||||
|  |           Derivative Works a copy of this License; and | ||||||
|  |  | ||||||
|  |       (b) You must cause any modified files to carry prominent notices | ||||||
|  |           stating that You changed the files; and | ||||||
|  |  | ||||||
|  |       (c) You must retain, in the Source form of any Derivative Works | ||||||
|  |           that You distribute, all copyright, patent, trademark, and | ||||||
|  |           attribution notices from the Source form of the Work, | ||||||
|  |           excluding those notices that do not pertain to any part of | ||||||
|  |           the Derivative Works; and | ||||||
|  |  | ||||||
|  |       (d) If the Work includes a "NOTICE" text file as part of its | ||||||
|  |           distribution, then any Derivative Works that You distribute must | ||||||
|  |           include a readable copy of the attribution notices contained | ||||||
|  |           within such NOTICE file, excluding those notices that do not | ||||||
|  |           pertain to any part of the Derivative Works, in at least one | ||||||
|  |           of the following places: within a NOTICE text file distributed | ||||||
|  |           as part of the Derivative Works; within the Source form or | ||||||
|  |           documentation, if provided along with the Derivative Works; or, | ||||||
|  |           within a display generated by the Derivative Works, if and | ||||||
|  |           wherever such third-party notices normally appear. The contents | ||||||
|  |           of the NOTICE file are for informational purposes only and | ||||||
|  |           do not modify the License. You may add Your own attribution | ||||||
|  |           notices within Derivative Works that You distribute, alongside | ||||||
|  |           or as an addendum to the NOTICE text from the Work, provided | ||||||
|  |           that such additional attribution notices cannot be construed | ||||||
|  |           as modifying the License. | ||||||
|  |  | ||||||
|  |       You may add Your own copyright statement to Your modifications and | ||||||
|  |       may provide additional or different license terms and conditions | ||||||
|  |       for use, reproduction, or distribution of Your modifications, or | ||||||
|  |       for any such Derivative Works as a whole, provided Your use, | ||||||
|  |       reproduction, and distribution of the Work otherwise complies with | ||||||
|  |       the conditions stated in this License. | ||||||
|  |  | ||||||
|  |    5. Submission of Contributions. Unless You explicitly state otherwise, | ||||||
|  |       any Contribution intentionally submitted for inclusion in the Work | ||||||
|  |       by You to the Licensor shall be under the terms and conditions of | ||||||
|  |       this License, without any additional terms or conditions. | ||||||
|  |       Notwithstanding the above, nothing herein shall supersede or modify | ||||||
|  |       the terms of any separate license agreement you may have executed | ||||||
|  |       with Licensor regarding such Contributions. | ||||||
|  |  | ||||||
|  |    6. Trademarks. This License does not grant permission to use the trade | ||||||
|  |       names, trademarks, service marks, or product names of the Licensor, | ||||||
|  |       except as required for reasonable and customary use in describing the | ||||||
|  |       origin of the Work and reproducing the content of the NOTICE file. | ||||||
|  |  | ||||||
|  |    7. Disclaimer of Warranty. Unless required by applicable law or | ||||||
|  |       agreed to in writing, Licensor provides the Work (and each | ||||||
|  |       Contributor provides its Contributions) on an "AS IS" BASIS, | ||||||
|  |       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | ||||||
|  |       implied, including, without limitation, any warranties or conditions | ||||||
|  |       of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A | ||||||
|  |       PARTICULAR PURPOSE. You are solely responsible for determining the | ||||||
|  |       appropriateness of using or redistributing the Work and assume any | ||||||
|  |       risks associated with Your exercise of permissions under this License. | ||||||
|  |  | ||||||
|  |    8. Limitation of Liability. In no event and under no legal theory, | ||||||
|  |       whether in tort (including negligence), contract, or otherwise, | ||||||
|  |       unless required by applicable law (such as deliberate and grossly | ||||||
|  |       negligent acts) or agreed to in writing, shall any Contributor be | ||||||
|  |       liable to You for damages, including any direct, indirect, special, | ||||||
|  |       incidental, or consequential damages of any character arising as a | ||||||
|  |       result of this License or out of the use or inability to use the | ||||||
|  |       Work (including but not limited to damages for loss of goodwill, | ||||||
|  |       work stoppage, computer failure or malfunction, or any and all | ||||||
|  |       other commercial damages or losses), even if such Contributor | ||||||
|  |       has been advised of the possibility of such damages. | ||||||
|  |  | ||||||
|  |    9. Accepting Warranty or Additional Liability. While redistributing | ||||||
|  |       the Work or Derivative Works thereof, You may choose to offer, | ||||||
|  |       and charge a fee for, acceptance of support, warranty, indemnity, | ||||||
|  |       or other liability obligations and/or rights consistent with this | ||||||
|  |       License. However, in accepting such obligations, You may act only | ||||||
|  |       on Your own behalf and on Your sole responsibility, not on behalf | ||||||
|  |       of any other Contributor, and only if You agree to indemnify, | ||||||
|  |       defend, and hold each Contributor harmless for any liability | ||||||
|  |       incurred by, or claims asserted against, such Contributor by reason | ||||||
|  |       of your accepting any such warranty or additional liability. | ||||||
|  |  | ||||||
|  |    END OF TERMS AND CONDITIONS | ||||||
|  |  | ||||||
|  |    Copyright 2013-2018 Docker, Inc. | ||||||
|  |  | ||||||
|  |    Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |    you may not use this file except in compliance with the License. | ||||||
|  |    You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |        https://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  |    Unless required by applicable law or agreed to in writing, software | ||||||
|  |    distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |    See the License for the specific language governing permissions and | ||||||
|  |    limitations under the License. | ||||||
							
								
								
									
										19
									
								
								vendor/github.com/docker/docker/NOTICE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								vendor/github.com/docker/docker/NOTICE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | |||||||
|  | Docker | ||||||
|  | Copyright 2012-2017 Docker, Inc. | ||||||
|  |  | ||||||
|  | This product includes software developed at Docker, Inc. (https://www.docker.com). | ||||||
|  |  | ||||||
|  | This product contains software (https://github.com/kr/pty) developed | ||||||
|  | by Keith Rarick, licensed under the MIT License. | ||||||
|  |  | ||||||
|  | The following is courtesy of our legal counsel: | ||||||
|  |  | ||||||
|  |  | ||||||
|  | Use and transfer of Docker may be subject to certain restrictions by the | ||||||
|  | United States and other governments. | ||||||
|  | It is your responsibility to ensure that your use and/or transfer does not | ||||||
|  | violate applicable laws. | ||||||
|  |  | ||||||
|  | For more information, please see https://www.bis.doc.gov | ||||||
|  |  | ||||||
|  | See also https://www.apache.org/dev/crypto.html and/or seek legal counsel. | ||||||
							
								
								
									
										42
									
								
								vendor/github.com/docker/docker/api/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								vendor/github.com/docker/docker/api/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | |||||||
|  | # Working on the Engine API | ||||||
|  |  | ||||||
|  | The Engine API is an HTTP API used by the command-line client to communicate with the daemon. It can also be used by third-party software to control the daemon. | ||||||
|  |  | ||||||
|  | It consists of various components in this repository: | ||||||
|  |  | ||||||
|  | - `api/swagger.yaml` A Swagger definition of the API. | ||||||
|  | - `api/types/` Types shared by both the client and server, representing various objects, options, responses, etc. Most are written manually, but some are automatically generated from the Swagger definition. See [#27919](https://github.com/docker/docker/issues/27919) for progress on this. | ||||||
|  | - `cli/` The command-line client. | ||||||
|  | - `client/` The Go client used by the command-line client. It can also be used by third-party Go programs. | ||||||
|  | - `daemon/` The daemon, which serves the API. | ||||||
|  |  | ||||||
|  | ## Swagger definition | ||||||
|  |  | ||||||
|  | The API is defined by the [Swagger](http://swagger.io/specification/) definition in `api/swagger.yaml`. This definition can be used to: | ||||||
|  |  | ||||||
|  | 1. Automatically generate documentation. | ||||||
|  | 2. Automatically generate the Go server and client. (A work-in-progress.) | ||||||
|  | 3. Provide a machine readable version of the API for introspecting what it can do, automatically generating clients for other languages, etc. | ||||||
|  |  | ||||||
|  | ## Updating the API documentation | ||||||
|  |  | ||||||
|  | The API documentation is generated entirely from `api/swagger.yaml`. If you make updates to the API, edit this file to represent the change in the documentation. | ||||||
|  |  | ||||||
|  | The file is split into two main sections: | ||||||
|  |  | ||||||
|  | - `definitions`, which defines re-usable objects used in requests and responses | ||||||
|  | - `paths`, which defines the API endpoints (and some inline objects which don't need to be reusable) | ||||||
|  |  | ||||||
|  | To make an edit, first look for the endpoint you want to edit under `paths`, then make the required edits. Endpoints may reference reusable objects with `$ref`, which can be found in the `definitions` section. | ||||||
|  |  | ||||||
|  | There is hopefully enough example material in the file for you to copy a similar pattern from elsewhere in the file (e.g. adding new fields or endpoints), but for the full reference, see the [Swagger specification](https://github.com/docker/docker/issues/27919). | ||||||
|  |  | ||||||
|  | `swagger.yaml` is validated by `hack/validate/swagger` to ensure it is a valid Swagger definition. This is useful when making edits to ensure you are doing the right thing. | ||||||
|  |  | ||||||
|  | ## Viewing the API documentation | ||||||
|  |  | ||||||
|  | When you make edits to `swagger.yaml`, you may want to check the generated API documentation to ensure it renders correctly. | ||||||
|  |  | ||||||
|  | Run `make swagger-docs` and a preview will be running at `http://localhost`. Some of the styling may be incorrect, but you'll be able to ensure that it is generating the correct documentation. | ||||||
|  |  | ||||||
|  | The production documentation is generated by vendoring `swagger.yaml` into [docker/docker.github.io](https://github.com/docker/docker.github.io). | ||||||
							
								
								
									
										11
									
								
								vendor/github.com/docker/docker/api/common.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								vendor/github.com/docker/docker/api/common.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | |||||||
|  | package api // import "github.com/docker/docker/api" | ||||||
|  |  | ||||||
|  | // Common constants for daemon and client. | ||||||
|  | const ( | ||||||
|  | 	// DefaultVersion of Current REST API | ||||||
|  | 	DefaultVersion = "1.40" | ||||||
|  |  | ||||||
|  | 	// NoBaseImageSpecifier is the symbol used by the FROM | ||||||
|  | 	// command to specify that no base image is to be used. | ||||||
|  | 	NoBaseImageSpecifier = "scratch" | ||||||
|  | ) | ||||||
							
								
								
									
										6
									
								
								vendor/github.com/docker/docker/api/common_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								vendor/github.com/docker/docker/api/common_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | |||||||
|  | // +build !windows | ||||||
|  |  | ||||||
|  | package api // import "github.com/docker/docker/api" | ||||||
|  |  | ||||||
|  | // MinVersion represents Minimum REST API version supported | ||||||
|  | const MinVersion = "1.12" | ||||||
							
								
								
									
										8
									
								
								vendor/github.com/docker/docker/api/common_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								vendor/github.com/docker/docker/api/common_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | |||||||
|  | package api // import "github.com/docker/docker/api" | ||||||
|  |  | ||||||
|  | // MinVersion represents Minimum REST API version supported | ||||||
|  | // Technically the first daemon API version released on Windows is v1.25 in | ||||||
|  | // engine version 1.13. However, some clients are explicitly using downlevel | ||||||
|  | // APIs (e.g. docker-compose v2.1 file format) and that is just too restrictive. | ||||||
|  | // Hence also allowing 1.24 on Windows. | ||||||
|  | const MinVersion string = "1.24" | ||||||
							
								
								
									
										12
									
								
								vendor/github.com/docker/docker/api/swagger-gen.yaml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								vendor/github.com/docker/docker/api/swagger-gen.yaml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | |||||||
|  |  | ||||||
|  | layout: | ||||||
|  |   models: | ||||||
|  |     - name: definition | ||||||
|  |       source: asset:model | ||||||
|  |       target: "{{ joinFilePath .Target .ModelPackage }}" | ||||||
|  |       file_name: "{{ (snakize (pascalize .Name)) }}.go" | ||||||
|  |   operations: | ||||||
|  |     - name: handler | ||||||
|  |       source: asset:serverOperation | ||||||
|  |       target: "{{ joinFilePath .Target .APIPackage .Package }}" | ||||||
|  |       file_name: "{{ (snakize (pascalize .Name)) }}.go" | ||||||
							
								
								
									
										10414
									
								
								vendor/github.com/docker/docker/api/swagger.yaml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										10414
									
								
								vendor/github.com/docker/docker/api/swagger.yaml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										22
									
								
								vendor/github.com/docker/docker/api/types/auth.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								vendor/github.com/docker/docker/api/types/auth.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | |||||||
|  | package types // import "github.com/docker/docker/api/types" | ||||||
|  |  | ||||||
|  | // AuthConfig contains authorization information for connecting to a Registry | ||||||
|  | type AuthConfig struct { | ||||||
|  | 	Username string `json:"username,omitempty"` | ||||||
|  | 	Password string `json:"password,omitempty"` | ||||||
|  | 	Auth     string `json:"auth,omitempty"` | ||||||
|  |  | ||||||
|  | 	// Email is an optional value associated with the username. | ||||||
|  | 	// This field is deprecated and will be removed in a later | ||||||
|  | 	// version of docker. | ||||||
|  | 	Email string `json:"email,omitempty"` | ||||||
|  |  | ||||||
|  | 	ServerAddress string `json:"serveraddress,omitempty"` | ||||||
|  |  | ||||||
|  | 	// IdentityToken is used to authenticate the user and get | ||||||
|  | 	// an access token for the registry. | ||||||
|  | 	IdentityToken string `json:"identitytoken,omitempty"` | ||||||
|  |  | ||||||
|  | 	// RegistryToken is a bearer token to be sent to a registry | ||||||
|  | 	RegistryToken string `json:"registrytoken,omitempty"` | ||||||
|  | } | ||||||
							
								
								
									
										23
									
								
								vendor/github.com/docker/docker/api/types/blkiodev/blkio.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								vendor/github.com/docker/docker/api/types/blkiodev/blkio.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | |||||||
|  | package blkiodev // import "github.com/docker/docker/api/types/blkiodev" | ||||||
|  |  | ||||||
|  | import "fmt" | ||||||
|  |  | ||||||
|  | // WeightDevice is a structure that holds device:weight pair | ||||||
|  | type WeightDevice struct { | ||||||
|  | 	Path   string | ||||||
|  | 	Weight uint16 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (w *WeightDevice) String() string { | ||||||
|  | 	return fmt.Sprintf("%s:%d", w.Path, w.Weight) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ThrottleDevice is a structure that holds device:rate_per_second pair | ||||||
|  | type ThrottleDevice struct { | ||||||
|  | 	Path string | ||||||
|  | 	Rate uint64 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t *ThrottleDevice) String() string { | ||||||
|  | 	return fmt.Sprintf("%s:%d", t.Path, t.Rate) | ||||||
|  | } | ||||||
							
								
								
									
										415
									
								
								vendor/github.com/docker/docker/api/types/client.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										415
									
								
								vendor/github.com/docker/docker/api/types/client.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,415 @@ | |||||||
|  | package types // import "github.com/docker/docker/api/types" | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"bufio" | ||||||
|  | 	"io" | ||||||
|  | 	"net" | ||||||
|  |  | ||||||
|  | 	"github.com/docker/docker/api/types/container" | ||||||
|  | 	"github.com/docker/docker/api/types/filters" | ||||||
|  | 	units "github.com/docker/go-units" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // CheckpointCreateOptions holds parameters to create a checkpoint from a container | ||||||
|  | type CheckpointCreateOptions struct { | ||||||
|  | 	CheckpointID  string | ||||||
|  | 	CheckpointDir string | ||||||
|  | 	Exit          bool | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // CheckpointListOptions holds parameters to list checkpoints for a container | ||||||
|  | type CheckpointListOptions struct { | ||||||
|  | 	CheckpointDir string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // CheckpointDeleteOptions holds parameters to delete a checkpoint from a container | ||||||
|  | type CheckpointDeleteOptions struct { | ||||||
|  | 	CheckpointID  string | ||||||
|  | 	CheckpointDir string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ContainerAttachOptions holds parameters to attach to a container. | ||||||
|  | type ContainerAttachOptions struct { | ||||||
|  | 	Stream     bool | ||||||
|  | 	Stdin      bool | ||||||
|  | 	Stdout     bool | ||||||
|  | 	Stderr     bool | ||||||
|  | 	DetachKeys string | ||||||
|  | 	Logs       bool | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ContainerCommitOptions holds parameters to commit changes into a container. | ||||||
|  | type ContainerCommitOptions struct { | ||||||
|  | 	Reference string | ||||||
|  | 	Comment   string | ||||||
|  | 	Author    string | ||||||
|  | 	Changes   []string | ||||||
|  | 	Pause     bool | ||||||
|  | 	Config    *container.Config | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ContainerExecInspect holds information returned by exec inspect. | ||||||
|  | type ContainerExecInspect struct { | ||||||
|  | 	ExecID      string | ||||||
|  | 	ContainerID string | ||||||
|  | 	Running     bool | ||||||
|  | 	ExitCode    int | ||||||
|  | 	Pid         int | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ContainerListOptions holds parameters to list containers with. | ||||||
|  | type ContainerListOptions struct { | ||||||
|  | 	Quiet   bool | ||||||
|  | 	Size    bool | ||||||
|  | 	All     bool | ||||||
|  | 	Latest  bool | ||||||
|  | 	Since   string | ||||||
|  | 	Before  string | ||||||
|  | 	Limit   int | ||||||
|  | 	Filters filters.Args | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ContainerLogsOptions holds parameters to filter logs with. | ||||||
|  | type ContainerLogsOptions struct { | ||||||
|  | 	ShowStdout bool | ||||||
|  | 	ShowStderr bool | ||||||
|  | 	Since      string | ||||||
|  | 	Until      string | ||||||
|  | 	Timestamps bool | ||||||
|  | 	Follow     bool | ||||||
|  | 	Tail       string | ||||||
|  | 	Details    bool | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ContainerRemoveOptions holds parameters to remove containers. | ||||||
|  | type ContainerRemoveOptions struct { | ||||||
|  | 	RemoveVolumes bool | ||||||
|  | 	RemoveLinks   bool | ||||||
|  | 	Force         bool | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ContainerStartOptions holds parameters to start containers. | ||||||
|  | type ContainerStartOptions struct { | ||||||
|  | 	CheckpointID  string | ||||||
|  | 	CheckpointDir string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // CopyToContainerOptions holds information | ||||||
|  | // about files to copy into a container | ||||||
|  | type CopyToContainerOptions struct { | ||||||
|  | 	AllowOverwriteDirWithFile bool | ||||||
|  | 	CopyUIDGID                bool | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // EventsOptions holds parameters to filter events with. | ||||||
|  | type EventsOptions struct { | ||||||
|  | 	Since   string | ||||||
|  | 	Until   string | ||||||
|  | 	Filters filters.Args | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // NetworkListOptions holds parameters to filter the list of networks with. | ||||||
|  | type NetworkListOptions struct { | ||||||
|  | 	Filters filters.Args | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // HijackedResponse holds connection information for a hijacked request. | ||||||
|  | type HijackedResponse struct { | ||||||
|  | 	Conn   net.Conn | ||||||
|  | 	Reader *bufio.Reader | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Close closes the hijacked connection and reader. | ||||||
|  | func (h *HijackedResponse) Close() { | ||||||
|  | 	h.Conn.Close() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // CloseWriter is an interface that implements structs | ||||||
|  | // that close input streams to prevent from writing. | ||||||
|  | type CloseWriter interface { | ||||||
|  | 	CloseWrite() error | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // CloseWrite closes a readWriter for writing. | ||||||
|  | func (h *HijackedResponse) CloseWrite() error { | ||||||
|  | 	if conn, ok := h.Conn.(CloseWriter); ok { | ||||||
|  | 		return conn.CloseWrite() | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ImageBuildOptions holds the information | ||||||
|  | // necessary to build images. | ||||||
|  | type ImageBuildOptions struct { | ||||||
|  | 	Tags           []string | ||||||
|  | 	SuppressOutput bool | ||||||
|  | 	RemoteContext  string | ||||||
|  | 	NoCache        bool | ||||||
|  | 	Remove         bool | ||||||
|  | 	ForceRemove    bool | ||||||
|  | 	PullParent     bool | ||||||
|  | 	Isolation      container.Isolation | ||||||
|  | 	CPUSetCPUs     string | ||||||
|  | 	CPUSetMems     string | ||||||
|  | 	CPUShares      int64 | ||||||
|  | 	CPUQuota       int64 | ||||||
|  | 	CPUPeriod      int64 | ||||||
|  | 	Memory         int64 | ||||||
|  | 	MemorySwap     int64 | ||||||
|  | 	CgroupParent   string | ||||||
|  | 	NetworkMode    string | ||||||
|  | 	ShmSize        int64 | ||||||
|  | 	Dockerfile     string | ||||||
|  | 	Ulimits        []*units.Ulimit | ||||||
|  | 	// BuildArgs needs to be a *string instead of just a string so that | ||||||
|  | 	// we can tell the difference between "" (empty string) and no value | ||||||
|  | 	// at all (nil). See the parsing of buildArgs in | ||||||
|  | 	// api/server/router/build/build_routes.go for even more info. | ||||||
|  | 	BuildArgs   map[string]*string | ||||||
|  | 	AuthConfigs map[string]AuthConfig | ||||||
|  | 	Context     io.Reader | ||||||
|  | 	Labels      map[string]string | ||||||
|  | 	// squash the resulting image's layers to the parent | ||||||
|  | 	// preserves the original image and creates a new one from the parent with all | ||||||
|  | 	// the changes applied to a single layer | ||||||
|  | 	Squash bool | ||||||
|  | 	// CacheFrom specifies images that are used for matching cache. Images | ||||||
|  | 	// specified here do not need to have a valid parent chain to match cache. | ||||||
|  | 	CacheFrom   []string | ||||||
|  | 	SecurityOpt []string | ||||||
|  | 	ExtraHosts  []string // List of extra hosts | ||||||
|  | 	Target      string | ||||||
|  | 	SessionID   string | ||||||
|  | 	Platform    string | ||||||
|  | 	// Version specifies the version of the unerlying builder to use | ||||||
|  | 	Version BuilderVersion | ||||||
|  | 	// BuildID is an optional identifier that can be passed together with the | ||||||
|  | 	// build request. The same identifier can be used to gracefully cancel the | ||||||
|  | 	// build with the cancel request. | ||||||
|  | 	BuildID string | ||||||
|  | 	// Outputs defines configurations for exporting build results. Only supported | ||||||
|  | 	// in BuildKit mode | ||||||
|  | 	Outputs []ImageBuildOutput | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ImageBuildOutput defines configuration for exporting a build result | ||||||
|  | type ImageBuildOutput struct { | ||||||
|  | 	Type  string | ||||||
|  | 	Attrs map[string]string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // BuilderVersion sets the version of underlying builder to use | ||||||
|  | type BuilderVersion string | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	// BuilderV1 is the first generation builder in docker daemon | ||||||
|  | 	BuilderV1 BuilderVersion = "1" | ||||||
|  | 	// BuilderBuildKit is builder based on moby/buildkit project | ||||||
|  | 	BuilderBuildKit = "2" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // ImageBuildResponse holds information | ||||||
|  | // returned by a server after building | ||||||
|  | // an image. | ||||||
|  | type ImageBuildResponse struct { | ||||||
|  | 	Body   io.ReadCloser | ||||||
|  | 	OSType string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ImageCreateOptions holds information to create images. | ||||||
|  | type ImageCreateOptions struct { | ||||||
|  | 	RegistryAuth string // RegistryAuth is the base64 encoded credentials for the registry. | ||||||
|  | 	Platform     string // Platform is the target platform of the image if it needs to be pulled from the registry. | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ImageImportSource holds source information for ImageImport | ||||||
|  | type ImageImportSource struct { | ||||||
|  | 	Source     io.Reader // Source is the data to send to the server to create this image from. You must set SourceName to "-" to leverage this. | ||||||
|  | 	SourceName string    // SourceName is the name of the image to pull. Set to "-" to leverage the Source attribute. | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ImageImportOptions holds information to import images from the client host. | ||||||
|  | type ImageImportOptions struct { | ||||||
|  | 	Tag      string   // Tag is the name to tag this image with. This attribute is deprecated. | ||||||
|  | 	Message  string   // Message is the message to tag the image with | ||||||
|  | 	Changes  []string // Changes are the raw changes to apply to this image | ||||||
|  | 	Platform string   // Platform is the target platform of the image | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ImageListOptions holds parameters to filter the list of images with. | ||||||
|  | type ImageListOptions struct { | ||||||
|  | 	All     bool | ||||||
|  | 	Filters filters.Args | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ImageLoadResponse returns information to the client about a load process. | ||||||
|  | type ImageLoadResponse struct { | ||||||
|  | 	// Body must be closed to avoid a resource leak | ||||||
|  | 	Body io.ReadCloser | ||||||
|  | 	JSON bool | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ImagePullOptions holds information to pull images. | ||||||
|  | type ImagePullOptions struct { | ||||||
|  | 	All           bool | ||||||
|  | 	RegistryAuth  string // RegistryAuth is the base64 encoded credentials for the registry | ||||||
|  | 	PrivilegeFunc RequestPrivilegeFunc | ||||||
|  | 	Platform      string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // RequestPrivilegeFunc is a function interface that | ||||||
|  | // clients can supply to retry operations after | ||||||
|  | // getting an authorization error. | ||||||
|  | // This function returns the registry authentication | ||||||
|  | // header value in base 64 format, or an error | ||||||
|  | // if the privilege request fails. | ||||||
|  | type RequestPrivilegeFunc func() (string, error) | ||||||
|  |  | ||||||
|  | //ImagePushOptions holds information to push images. | ||||||
|  | type ImagePushOptions ImagePullOptions | ||||||
|  |  | ||||||
|  | // ImageRemoveOptions holds parameters to remove images. | ||||||
|  | type ImageRemoveOptions struct { | ||||||
|  | 	Force         bool | ||||||
|  | 	PruneChildren bool | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ImageSearchOptions holds parameters to search images with. | ||||||
|  | type ImageSearchOptions struct { | ||||||
|  | 	RegistryAuth  string | ||||||
|  | 	PrivilegeFunc RequestPrivilegeFunc | ||||||
|  | 	Filters       filters.Args | ||||||
|  | 	Limit         int | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ResizeOptions holds parameters to resize a tty. | ||||||
|  | // It can be used to resize container ttys and | ||||||
|  | // exec process ttys too. | ||||||
|  | type ResizeOptions struct { | ||||||
|  | 	Height uint | ||||||
|  | 	Width  uint | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // NodeListOptions holds parameters to list nodes with. | ||||||
|  | type NodeListOptions struct { | ||||||
|  | 	Filters filters.Args | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // NodeRemoveOptions holds parameters to remove nodes with. | ||||||
|  | type NodeRemoveOptions struct { | ||||||
|  | 	Force bool | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ServiceCreateOptions contains the options to use when creating a service. | ||||||
|  | type ServiceCreateOptions struct { | ||||||
|  | 	// EncodedRegistryAuth is the encoded registry authorization credentials to | ||||||
|  | 	// use when updating the service. | ||||||
|  | 	// | ||||||
|  | 	// This field follows the format of the X-Registry-Auth header. | ||||||
|  | 	EncodedRegistryAuth string | ||||||
|  |  | ||||||
|  | 	// QueryRegistry indicates whether the service update requires | ||||||
|  | 	// contacting a registry. A registry may be contacted to retrieve | ||||||
|  | 	// the image digest and manifest, which in turn can be used to update | ||||||
|  | 	// platform or other information about the service. | ||||||
|  | 	QueryRegistry bool | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ServiceCreateResponse contains the information returned to a client | ||||||
|  | // on the creation of a new service. | ||||||
|  | type ServiceCreateResponse struct { | ||||||
|  | 	// ID is the ID of the created service. | ||||||
|  | 	ID string | ||||||
|  | 	// Warnings is a set of non-fatal warning messages to pass on to the user. | ||||||
|  | 	Warnings []string `json:",omitempty"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Values for RegistryAuthFrom in ServiceUpdateOptions | ||||||
|  | const ( | ||||||
|  | 	RegistryAuthFromSpec         = "spec" | ||||||
|  | 	RegistryAuthFromPreviousSpec = "previous-spec" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // ServiceUpdateOptions contains the options to be used for updating services. | ||||||
|  | type ServiceUpdateOptions struct { | ||||||
|  | 	// EncodedRegistryAuth is the encoded registry authorization credentials to | ||||||
|  | 	// use when updating the service. | ||||||
|  | 	// | ||||||
|  | 	// This field follows the format of the X-Registry-Auth header. | ||||||
|  | 	EncodedRegistryAuth string | ||||||
|  |  | ||||||
|  | 	// TODO(stevvooe): Consider moving the version parameter of ServiceUpdate | ||||||
|  | 	// into this field. While it does open API users up to racy writes, most | ||||||
|  | 	// users may not need that level of consistency in practice. | ||||||
|  |  | ||||||
|  | 	// RegistryAuthFrom specifies where to find the registry authorization | ||||||
|  | 	// credentials if they are not given in EncodedRegistryAuth. Valid | ||||||
|  | 	// values are "spec" and "previous-spec". | ||||||
|  | 	RegistryAuthFrom string | ||||||
|  |  | ||||||
|  | 	// Rollback indicates whether a server-side rollback should be | ||||||
|  | 	// performed. When this is set, the provided spec will be ignored. | ||||||
|  | 	// The valid values are "previous" and "none". An empty value is the | ||||||
|  | 	// same as "none". | ||||||
|  | 	Rollback string | ||||||
|  |  | ||||||
|  | 	// QueryRegistry indicates whether the service update requires | ||||||
|  | 	// contacting a registry. A registry may be contacted to retrieve | ||||||
|  | 	// the image digest and manifest, which in turn can be used to update | ||||||
|  | 	// platform or other information about the service. | ||||||
|  | 	QueryRegistry bool | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ServiceListOptions holds parameters to list services with. | ||||||
|  | type ServiceListOptions struct { | ||||||
|  | 	Filters filters.Args | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ServiceInspectOptions holds parameters related to the "service inspect" | ||||||
|  | // operation. | ||||||
|  | type ServiceInspectOptions struct { | ||||||
|  | 	InsertDefaults bool | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // TaskListOptions holds parameters to list tasks with. | ||||||
|  | type TaskListOptions struct { | ||||||
|  | 	Filters filters.Args | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // PluginRemoveOptions holds parameters to remove plugins. | ||||||
|  | type PluginRemoveOptions struct { | ||||||
|  | 	Force bool | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // PluginEnableOptions holds parameters to enable plugins. | ||||||
|  | type PluginEnableOptions struct { | ||||||
|  | 	Timeout int | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // PluginDisableOptions holds parameters to disable plugins. | ||||||
|  | type PluginDisableOptions struct { | ||||||
|  | 	Force bool | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // PluginInstallOptions holds parameters to install a plugin. | ||||||
|  | type PluginInstallOptions struct { | ||||||
|  | 	Disabled              bool | ||||||
|  | 	AcceptAllPermissions  bool | ||||||
|  | 	RegistryAuth          string // RegistryAuth is the base64 encoded credentials for the registry | ||||||
|  | 	RemoteRef             string // RemoteRef is the plugin name on the registry | ||||||
|  | 	PrivilegeFunc         RequestPrivilegeFunc | ||||||
|  | 	AcceptPermissionsFunc func(PluginPrivileges) (bool, error) | ||||||
|  | 	Args                  []string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // SwarmUnlockKeyResponse contains the response for Engine API: | ||||||
|  | // GET /swarm/unlockkey | ||||||
|  | type SwarmUnlockKeyResponse struct { | ||||||
|  | 	// UnlockKey is the unlock key in ASCII-armored format. | ||||||
|  | 	UnlockKey string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // PluginCreateOptions hold all options to plugin create. | ||||||
|  | type PluginCreateOptions struct { | ||||||
|  | 	RepoName string | ||||||
|  | } | ||||||
							
								
								
									
										64
									
								
								vendor/github.com/docker/docker/api/types/configs.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								vendor/github.com/docker/docker/api/types/configs.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,64 @@ | |||||||
|  | package types // import "github.com/docker/docker/api/types" | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"github.com/docker/docker/api/types/container" | ||||||
|  | 	"github.com/docker/docker/api/types/network" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // configs holds structs used for internal communication between the | ||||||
|  | // frontend (such as an http server) and the backend (such as the | ||||||
|  | // docker daemon). | ||||||
|  |  | ||||||
|  | // ContainerCreateConfig is the parameter set to ContainerCreate() | ||||||
|  | type ContainerCreateConfig struct { | ||||||
|  | 	Name             string | ||||||
|  | 	Config           *container.Config | ||||||
|  | 	HostConfig       *container.HostConfig | ||||||
|  | 	NetworkingConfig *network.NetworkingConfig | ||||||
|  | 	AdjustCPUShares  bool | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ContainerRmConfig holds arguments for the container remove | ||||||
|  | // operation. This struct is used to tell the backend what operations | ||||||
|  | // to perform. | ||||||
|  | type ContainerRmConfig struct { | ||||||
|  | 	ForceRemove, RemoveVolume, RemoveLink bool | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ExecConfig is a small subset of the Config struct that holds the configuration | ||||||
|  | // for the exec feature of docker. | ||||||
|  | type ExecConfig struct { | ||||||
|  | 	User         string   // User that will run the command | ||||||
|  | 	Privileged   bool     // Is the container in privileged mode | ||||||
|  | 	Tty          bool     // Attach standard streams to a tty. | ||||||
|  | 	AttachStdin  bool     // Attach the standard input, makes possible user interaction | ||||||
|  | 	AttachStderr bool     // Attach the standard error | ||||||
|  | 	AttachStdout bool     // Attach the standard output | ||||||
|  | 	Detach       bool     // Execute in detach mode | ||||||
|  | 	DetachKeys   string   // Escape keys for detach | ||||||
|  | 	Env          []string // Environment variables | ||||||
|  | 	WorkingDir   string   // Working directory | ||||||
|  | 	Cmd          []string // Execution commands and args | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // PluginRmConfig holds arguments for plugin remove. | ||||||
|  | type PluginRmConfig struct { | ||||||
|  | 	ForceRemove bool | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // PluginEnableConfig holds arguments for plugin enable | ||||||
|  | type PluginEnableConfig struct { | ||||||
|  | 	Timeout int | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // PluginDisableConfig holds arguments for plugin disable. | ||||||
|  | type PluginDisableConfig struct { | ||||||
|  | 	ForceDisable bool | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // NetworkListConfig stores the options available for listing networks | ||||||
|  | type NetworkListConfig struct { | ||||||
|  | 	// TODO(@cpuguy83): naming is hard, this is pulled from what was being used in the router before moving here | ||||||
|  | 	Detailed bool | ||||||
|  | 	Verbose  bool | ||||||
|  | } | ||||||
							
								
								
									
										69
									
								
								vendor/github.com/docker/docker/api/types/container/config.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								vendor/github.com/docker/docker/api/types/container/config.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,69 @@ | |||||||
|  | package container // import "github.com/docker/docker/api/types/container" | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"time" | ||||||
|  |  | ||||||
|  | 	"github.com/docker/docker/api/types/strslice" | ||||||
|  | 	"github.com/docker/go-connections/nat" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // MinimumDuration puts a minimum on user configured duration. | ||||||
|  | // This is to prevent API error on time unit. For example, API may | ||||||
|  | // set 3 as healthcheck interval with intention of 3 seconds, but | ||||||
|  | // Docker interprets it as 3 nanoseconds. | ||||||
|  | const MinimumDuration = 1 * time.Millisecond | ||||||
|  |  | ||||||
|  | // HealthConfig holds configuration settings for the HEALTHCHECK feature. | ||||||
|  | type HealthConfig struct { | ||||||
|  | 	// Test is the test to perform to check that the container is healthy. | ||||||
|  | 	// An empty slice means to inherit the default. | ||||||
|  | 	// The options are: | ||||||
|  | 	// {} : inherit healthcheck | ||||||
|  | 	// {"NONE"} : disable healthcheck | ||||||
|  | 	// {"CMD", args...} : exec arguments directly | ||||||
|  | 	// {"CMD-SHELL", command} : run command with system's default shell | ||||||
|  | 	Test []string `json:",omitempty"` | ||||||
|  |  | ||||||
|  | 	// Zero means to inherit. Durations are expressed as integer nanoseconds. | ||||||
|  | 	Interval    time.Duration `json:",omitempty"` // Interval is the time to wait between checks. | ||||||
|  | 	Timeout     time.Duration `json:",omitempty"` // Timeout is the time to wait before considering the check to have hung. | ||||||
|  | 	StartPeriod time.Duration `json:",omitempty"` // The start period for the container to initialize before the retries starts to count down. | ||||||
|  |  | ||||||
|  | 	// Retries is the number of consecutive failures needed to consider a container as unhealthy. | ||||||
|  | 	// Zero means inherit. | ||||||
|  | 	Retries int `json:",omitempty"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Config contains the configuration data about a container. | ||||||
|  | // It should hold only portable information about the container. | ||||||
|  | // Here, "portable" means "independent from the host we are running on". | ||||||
|  | // Non-portable information *should* appear in HostConfig. | ||||||
|  | // All fields added to this struct must be marked `omitempty` to keep getting | ||||||
|  | // predictable hashes from the old `v1Compatibility` configuration. | ||||||
|  | type Config struct { | ||||||
|  | 	Hostname        string              // Hostname | ||||||
|  | 	Domainname      string              // Domainname | ||||||
|  | 	User            string              // User that will run the command(s) inside the container, also support user:group | ||||||
|  | 	AttachStdin     bool                // Attach the standard input, makes possible user interaction | ||||||
|  | 	AttachStdout    bool                // Attach the standard output | ||||||
|  | 	AttachStderr    bool                // Attach the standard error | ||||||
|  | 	ExposedPorts    nat.PortSet         `json:",omitempty"` // List of exposed ports | ||||||
|  | 	Tty             bool                // Attach standard streams to a tty, including stdin if it is not closed. | ||||||
|  | 	OpenStdin       bool                // Open stdin | ||||||
|  | 	StdinOnce       bool                // If true, close stdin after the 1 attached client disconnects. | ||||||
|  | 	Env             []string            // List of environment variable to set in the container | ||||||
|  | 	Cmd             strslice.StrSlice   // Command to run when starting the container | ||||||
|  | 	Healthcheck     *HealthConfig       `json:",omitempty"` // Healthcheck describes how to check the container is healthy | ||||||
|  | 	ArgsEscaped     bool                `json:",omitempty"` // True if command is already escaped (meaning treat as a command line) (Windows specific). | ||||||
|  | 	Image           string              // Name of the image as it was passed by the operator (e.g. could be symbolic) | ||||||
|  | 	Volumes         map[string]struct{} // List of volumes (mounts) used for the container | ||||||
|  | 	WorkingDir      string              // Current directory (PWD) in the command will be launched | ||||||
|  | 	Entrypoint      strslice.StrSlice   // Entrypoint to run when starting the container | ||||||
|  | 	NetworkDisabled bool                `json:",omitempty"` // Is network disabled | ||||||
|  | 	MacAddress      string              `json:",omitempty"` // Mac Address of the container | ||||||
|  | 	OnBuild         []string            // ONBUILD metadata that were defined on the image Dockerfile | ||||||
|  | 	Labels          map[string]string   // List of labels set to this container | ||||||
|  | 	StopSignal      string              `json:",omitempty"` // Signal to stop a container | ||||||
|  | 	StopTimeout     *int                `json:",omitempty"` // Timeout (in seconds) to stop a container | ||||||
|  | 	Shell           strslice.StrSlice   `json:",omitempty"` // Shell for shell-form of RUN, CMD, ENTRYPOINT | ||||||
|  | } | ||||||
							
								
								
									
										21
									
								
								vendor/github.com/docker/docker/api/types/container/container_changes.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								vendor/github.com/docker/docker/api/types/container/container_changes.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | |||||||
|  | package container // import "github.com/docker/docker/api/types/container" | ||||||
|  |  | ||||||
|  | // ---------------------------------------------------------------------------- | ||||||
|  | // DO NOT EDIT THIS FILE | ||||||
|  | // This file was generated by `swagger generate operation` | ||||||
|  | // | ||||||
|  | // See hack/generate-swagger-api.sh | ||||||
|  | // ---------------------------------------------------------------------------- | ||||||
|  |  | ||||||
|  | // ContainerChangeResponseItem change item in response to ContainerChanges operation | ||||||
|  | // swagger:model ContainerChangeResponseItem | ||||||
|  | type ContainerChangeResponseItem struct { | ||||||
|  |  | ||||||
|  | 	// Kind of change | ||||||
|  | 	// Required: true | ||||||
|  | 	Kind uint8 `json:"Kind"` | ||||||
|  |  | ||||||
|  | 	// Path to file that has changed | ||||||
|  | 	// Required: true | ||||||
|  | 	Path string `json:"Path"` | ||||||
|  | } | ||||||
							
								
								
									
										21
									
								
								vendor/github.com/docker/docker/api/types/container/container_create.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								vendor/github.com/docker/docker/api/types/container/container_create.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | |||||||
|  | package container // import "github.com/docker/docker/api/types/container" | ||||||
|  |  | ||||||
|  | // ---------------------------------------------------------------------------- | ||||||
|  | // DO NOT EDIT THIS FILE | ||||||
|  | // This file was generated by `swagger generate operation` | ||||||
|  | // | ||||||
|  | // See hack/generate-swagger-api.sh | ||||||
|  | // ---------------------------------------------------------------------------- | ||||||
|  |  | ||||||
|  | // ContainerCreateCreatedBody OK response to ContainerCreate operation | ||||||
|  | // swagger:model ContainerCreateCreatedBody | ||||||
|  | type ContainerCreateCreatedBody struct { | ||||||
|  |  | ||||||
|  | 	// The ID of the created container | ||||||
|  | 	// Required: true | ||||||
|  | 	ID string `json:"Id"` | ||||||
|  |  | ||||||
|  | 	// Warnings encountered when creating the container | ||||||
|  | 	// Required: true | ||||||
|  | 	Warnings []string `json:"Warnings"` | ||||||
|  | } | ||||||
							
								
								
									
										21
									
								
								vendor/github.com/docker/docker/api/types/container/container_top.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								vendor/github.com/docker/docker/api/types/container/container_top.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | |||||||
|  | package container // import "github.com/docker/docker/api/types/container" | ||||||
|  |  | ||||||
|  | // ---------------------------------------------------------------------------- | ||||||
|  | // DO NOT EDIT THIS FILE | ||||||
|  | // This file was generated by `swagger generate operation` | ||||||
|  | // | ||||||
|  | // See hack/generate-swagger-api.sh | ||||||
|  | // ---------------------------------------------------------------------------- | ||||||
|  |  | ||||||
|  | // ContainerTopOKBody OK response to ContainerTop operation | ||||||
|  | // swagger:model ContainerTopOKBody | ||||||
|  | type ContainerTopOKBody struct { | ||||||
|  |  | ||||||
|  | 	// Each process running in the container, where each is process is an array of values corresponding to the titles | ||||||
|  | 	// Required: true | ||||||
|  | 	Processes [][]string `json:"Processes"` | ||||||
|  |  | ||||||
|  | 	// The ps column titles | ||||||
|  | 	// Required: true | ||||||
|  | 	Titles []string `json:"Titles"` | ||||||
|  | } | ||||||
							
								
								
									
										17
									
								
								vendor/github.com/docker/docker/api/types/container/container_update.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								vendor/github.com/docker/docker/api/types/container/container_update.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | |||||||
|  | package container // import "github.com/docker/docker/api/types/container" | ||||||
|  |  | ||||||
|  | // ---------------------------------------------------------------------------- | ||||||
|  | // DO NOT EDIT THIS FILE | ||||||
|  | // This file was generated by `swagger generate operation` | ||||||
|  | // | ||||||
|  | // See hack/generate-swagger-api.sh | ||||||
|  | // ---------------------------------------------------------------------------- | ||||||
|  |  | ||||||
|  | // ContainerUpdateOKBody OK response to ContainerUpdate operation | ||||||
|  | // swagger:model ContainerUpdateOKBody | ||||||
|  | type ContainerUpdateOKBody struct { | ||||||
|  |  | ||||||
|  | 	// warnings | ||||||
|  | 	// Required: true | ||||||
|  | 	Warnings []string `json:"Warnings"` | ||||||
|  | } | ||||||
							
								
								
									
										29
									
								
								vendor/github.com/docker/docker/api/types/container/container_wait.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								vendor/github.com/docker/docker/api/types/container/container_wait.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | |||||||
|  | package container // import "github.com/docker/docker/api/types/container" | ||||||
|  |  | ||||||
|  | // ---------------------------------------------------------------------------- | ||||||
|  | // DO NOT EDIT THIS FILE | ||||||
|  | // This file was generated by `swagger generate operation` | ||||||
|  | // | ||||||
|  | // See hack/generate-swagger-api.sh | ||||||
|  | // ---------------------------------------------------------------------------- | ||||||
|  |  | ||||||
|  | // ContainerWaitOKBodyError container waiting error, if any | ||||||
|  | // swagger:model ContainerWaitOKBodyError | ||||||
|  | type ContainerWaitOKBodyError struct { | ||||||
|  |  | ||||||
|  | 	// Details of an error | ||||||
|  | 	Message string `json:"Message,omitempty"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ContainerWaitOKBody OK response to ContainerWait operation | ||||||
|  | // swagger:model ContainerWaitOKBody | ||||||
|  | type ContainerWaitOKBody struct { | ||||||
|  |  | ||||||
|  | 	// error | ||||||
|  | 	// Required: true | ||||||
|  | 	Error *ContainerWaitOKBodyError `json:"Error"` | ||||||
|  |  | ||||||
|  | 	// Exit code of the container | ||||||
|  | 	// Required: true | ||||||
|  | 	StatusCode int64 `json:"StatusCode"` | ||||||
|  | } | ||||||
							
								
								
									
										425
									
								
								vendor/github.com/docker/docker/api/types/container/host_config.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										425
									
								
								vendor/github.com/docker/docker/api/types/container/host_config.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,425 @@ | |||||||
|  | package container // import "github.com/docker/docker/api/types/container" | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"strings" | ||||||
|  |  | ||||||
|  | 	"github.com/docker/docker/api/types/blkiodev" | ||||||
|  | 	"github.com/docker/docker/api/types/mount" | ||||||
|  | 	"github.com/docker/docker/api/types/strslice" | ||||||
|  | 	"github.com/docker/go-connections/nat" | ||||||
|  | 	"github.com/docker/go-units" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // Isolation represents the isolation technology of a container. The supported | ||||||
|  | // values are platform specific | ||||||
|  | type Isolation string | ||||||
|  |  | ||||||
|  | // IsDefault indicates the default isolation technology of a container. On Linux this | ||||||
|  | // is the native driver. On Windows, this is a Windows Server Container. | ||||||
|  | func (i Isolation) IsDefault() bool { | ||||||
|  | 	return strings.ToLower(string(i)) == "default" || string(i) == "" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // IsHyperV indicates the use of a Hyper-V partition for isolation | ||||||
|  | func (i Isolation) IsHyperV() bool { | ||||||
|  | 	return strings.ToLower(string(i)) == "hyperv" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // IsProcess indicates the use of process isolation | ||||||
|  | func (i Isolation) IsProcess() bool { | ||||||
|  | 	return strings.ToLower(string(i)) == "process" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	// IsolationEmpty is unspecified (same behavior as default) | ||||||
|  | 	IsolationEmpty = Isolation("") | ||||||
|  | 	// IsolationDefault is the default isolation mode on current daemon | ||||||
|  | 	IsolationDefault = Isolation("default") | ||||||
|  | 	// IsolationProcess is process isolation mode | ||||||
|  | 	IsolationProcess = Isolation("process") | ||||||
|  | 	// IsolationHyperV is HyperV isolation mode | ||||||
|  | 	IsolationHyperV = Isolation("hyperv") | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // IpcMode represents the container ipc stack. | ||||||
|  | type IpcMode string | ||||||
|  |  | ||||||
|  | // IsPrivate indicates whether the container uses its own private ipc namespace which can not be shared. | ||||||
|  | func (n IpcMode) IsPrivate() bool { | ||||||
|  | 	return n == "private" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // IsHost indicates whether the container shares the host's ipc namespace. | ||||||
|  | func (n IpcMode) IsHost() bool { | ||||||
|  | 	return n == "host" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // IsShareable indicates whether the container's ipc namespace can be shared with another container. | ||||||
|  | func (n IpcMode) IsShareable() bool { | ||||||
|  | 	return n == "shareable" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // IsContainer indicates whether the container uses another container's ipc namespace. | ||||||
|  | func (n IpcMode) IsContainer() bool { | ||||||
|  | 	parts := strings.SplitN(string(n), ":", 2) | ||||||
|  | 	return len(parts) > 1 && parts[0] == "container" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // IsNone indicates whether container IpcMode is set to "none". | ||||||
|  | func (n IpcMode) IsNone() bool { | ||||||
|  | 	return n == "none" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // IsEmpty indicates whether container IpcMode is empty | ||||||
|  | func (n IpcMode) IsEmpty() bool { | ||||||
|  | 	return n == "" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Valid indicates whether the ipc mode is valid. | ||||||
|  | func (n IpcMode) Valid() bool { | ||||||
|  | 	return n.IsEmpty() || n.IsNone() || n.IsPrivate() || n.IsHost() || n.IsShareable() || n.IsContainer() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Container returns the name of the container ipc stack is going to be used. | ||||||
|  | func (n IpcMode) Container() string { | ||||||
|  | 	parts := strings.SplitN(string(n), ":", 2) | ||||||
|  | 	if len(parts) > 1 && parts[0] == "container" { | ||||||
|  | 		return parts[1] | ||||||
|  | 	} | ||||||
|  | 	return "" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // NetworkMode represents the container network stack. | ||||||
|  | type NetworkMode string | ||||||
|  |  | ||||||
|  | // IsNone indicates whether container isn't using a network stack. | ||||||
|  | func (n NetworkMode) IsNone() bool { | ||||||
|  | 	return n == "none" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // IsDefault indicates whether container uses the default network stack. | ||||||
|  | func (n NetworkMode) IsDefault() bool { | ||||||
|  | 	return n == "default" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // IsPrivate indicates whether container uses its private network stack. | ||||||
|  | func (n NetworkMode) IsPrivate() bool { | ||||||
|  | 	return !(n.IsHost() || n.IsContainer()) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // IsContainer indicates whether container uses a container network stack. | ||||||
|  | func (n NetworkMode) IsContainer() bool { | ||||||
|  | 	parts := strings.SplitN(string(n), ":", 2) | ||||||
|  | 	return len(parts) > 1 && parts[0] == "container" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ConnectedContainer is the id of the container which network this container is connected to. | ||||||
|  | func (n NetworkMode) ConnectedContainer() string { | ||||||
|  | 	parts := strings.SplitN(string(n), ":", 2) | ||||||
|  | 	if len(parts) > 1 { | ||||||
|  | 		return parts[1] | ||||||
|  | 	} | ||||||
|  | 	return "" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | //UserDefined indicates user-created network | ||||||
|  | func (n NetworkMode) UserDefined() string { | ||||||
|  | 	if n.IsUserDefined() { | ||||||
|  | 		return string(n) | ||||||
|  | 	} | ||||||
|  | 	return "" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // UsernsMode represents userns mode in the container. | ||||||
|  | type UsernsMode string | ||||||
|  |  | ||||||
|  | // IsHost indicates whether the container uses the host's userns. | ||||||
|  | func (n UsernsMode) IsHost() bool { | ||||||
|  | 	return n == "host" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // IsPrivate indicates whether the container uses the a private userns. | ||||||
|  | func (n UsernsMode) IsPrivate() bool { | ||||||
|  | 	return !(n.IsHost()) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Valid indicates whether the userns is valid. | ||||||
|  | func (n UsernsMode) Valid() bool { | ||||||
|  | 	parts := strings.Split(string(n), ":") | ||||||
|  | 	switch mode := parts[0]; mode { | ||||||
|  | 	case "", "host": | ||||||
|  | 	default: | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	return true | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // CgroupSpec represents the cgroup to use for the container. | ||||||
|  | type CgroupSpec string | ||||||
|  |  | ||||||
|  | // IsContainer indicates whether the container is using another container cgroup | ||||||
|  | func (c CgroupSpec) IsContainer() bool { | ||||||
|  | 	parts := strings.SplitN(string(c), ":", 2) | ||||||
|  | 	return len(parts) > 1 && parts[0] == "container" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Valid indicates whether the cgroup spec is valid. | ||||||
|  | func (c CgroupSpec) Valid() bool { | ||||||
|  | 	return c.IsContainer() || c == "" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Container returns the name of the container whose cgroup will be used. | ||||||
|  | func (c CgroupSpec) Container() string { | ||||||
|  | 	parts := strings.SplitN(string(c), ":", 2) | ||||||
|  | 	if len(parts) > 1 { | ||||||
|  | 		return parts[1] | ||||||
|  | 	} | ||||||
|  | 	return "" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // UTSMode represents the UTS namespace of the container. | ||||||
|  | type UTSMode string | ||||||
|  |  | ||||||
|  | // IsPrivate indicates whether the container uses its private UTS namespace. | ||||||
|  | func (n UTSMode) IsPrivate() bool { | ||||||
|  | 	return !(n.IsHost()) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // IsHost indicates whether the container uses the host's UTS namespace. | ||||||
|  | func (n UTSMode) IsHost() bool { | ||||||
|  | 	return n == "host" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Valid indicates whether the UTS namespace is valid. | ||||||
|  | func (n UTSMode) Valid() bool { | ||||||
|  | 	parts := strings.Split(string(n), ":") | ||||||
|  | 	switch mode := parts[0]; mode { | ||||||
|  | 	case "", "host": | ||||||
|  | 	default: | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	return true | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // PidMode represents the pid namespace of the container. | ||||||
|  | type PidMode string | ||||||
|  |  | ||||||
|  | // IsPrivate indicates whether the container uses its own new pid namespace. | ||||||
|  | func (n PidMode) IsPrivate() bool { | ||||||
|  | 	return !(n.IsHost() || n.IsContainer()) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // IsHost indicates whether the container uses the host's pid namespace. | ||||||
|  | func (n PidMode) IsHost() bool { | ||||||
|  | 	return n == "host" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // IsContainer indicates whether the container uses a container's pid namespace. | ||||||
|  | func (n PidMode) IsContainer() bool { | ||||||
|  | 	parts := strings.SplitN(string(n), ":", 2) | ||||||
|  | 	return len(parts) > 1 && parts[0] == "container" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Valid indicates whether the pid namespace is valid. | ||||||
|  | func (n PidMode) Valid() bool { | ||||||
|  | 	parts := strings.Split(string(n), ":") | ||||||
|  | 	switch mode := parts[0]; mode { | ||||||
|  | 	case "", "host": | ||||||
|  | 	case "container": | ||||||
|  | 		if len(parts) != 2 || parts[1] == "" { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 	default: | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	return true | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Container returns the name of the container whose pid namespace is going to be used. | ||||||
|  | func (n PidMode) Container() string { | ||||||
|  | 	parts := strings.SplitN(string(n), ":", 2) | ||||||
|  | 	if len(parts) > 1 { | ||||||
|  | 		return parts[1] | ||||||
|  | 	} | ||||||
|  | 	return "" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // DeviceRequest represents a request for devices from a device driver. | ||||||
|  | // Used by GPU device drivers. | ||||||
|  | type DeviceRequest struct { | ||||||
|  | 	Driver       string            // Name of device driver | ||||||
|  | 	Count        int               // Number of devices to request (-1 = All) | ||||||
|  | 	DeviceIDs    []string          // List of device IDs as recognizable by the device driver | ||||||
|  | 	Capabilities [][]string        // An OR list of AND lists of device capabilities (e.g. "gpu") | ||||||
|  | 	Options      map[string]string // Options to pass onto the device driver | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // DeviceMapping represents the device mapping between the host and the container. | ||||||
|  | type DeviceMapping struct { | ||||||
|  | 	PathOnHost        string | ||||||
|  | 	PathInContainer   string | ||||||
|  | 	CgroupPermissions string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // RestartPolicy represents the restart policies of the container. | ||||||
|  | type RestartPolicy struct { | ||||||
|  | 	Name              string | ||||||
|  | 	MaximumRetryCount int | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // IsNone indicates whether the container has the "no" restart policy. | ||||||
|  | // This means the container will not automatically restart when exiting. | ||||||
|  | func (rp *RestartPolicy) IsNone() bool { | ||||||
|  | 	return rp.Name == "no" || rp.Name == "" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // IsAlways indicates whether the container has the "always" restart policy. | ||||||
|  | // This means the container will automatically restart regardless of the exit status. | ||||||
|  | func (rp *RestartPolicy) IsAlways() bool { | ||||||
|  | 	return rp.Name == "always" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // IsOnFailure indicates whether the container has the "on-failure" restart policy. | ||||||
|  | // This means the container will automatically restart of exiting with a non-zero exit status. | ||||||
|  | func (rp *RestartPolicy) IsOnFailure() bool { | ||||||
|  | 	return rp.Name == "on-failure" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // IsUnlessStopped indicates whether the container has the | ||||||
|  | // "unless-stopped" restart policy. This means the container will | ||||||
|  | // automatically restart unless user has put it to stopped state. | ||||||
|  | func (rp *RestartPolicy) IsUnlessStopped() bool { | ||||||
|  | 	return rp.Name == "unless-stopped" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // IsSame compares two RestartPolicy to see if they are the same | ||||||
|  | func (rp *RestartPolicy) IsSame(tp *RestartPolicy) bool { | ||||||
|  | 	return rp.Name == tp.Name && rp.MaximumRetryCount == tp.MaximumRetryCount | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // LogMode is a type to define the available modes for logging | ||||||
|  | // These modes affect how logs are handled when log messages start piling up. | ||||||
|  | type LogMode string | ||||||
|  |  | ||||||
|  | // Available logging modes | ||||||
|  | const ( | ||||||
|  | 	LogModeUnset            = "" | ||||||
|  | 	LogModeBlocking LogMode = "blocking" | ||||||
|  | 	LogModeNonBlock LogMode = "non-blocking" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // LogConfig represents the logging configuration of the container. | ||||||
|  | type LogConfig struct { | ||||||
|  | 	Type   string | ||||||
|  | 	Config map[string]string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Resources contains container's resources (cgroups config, ulimits...) | ||||||
|  | type Resources struct { | ||||||
|  | 	// Applicable to all platforms | ||||||
|  | 	CPUShares int64 `json:"CpuShares"` // CPU shares (relative weight vs. other containers) | ||||||
|  | 	Memory    int64 // Memory limit (in bytes) | ||||||
|  | 	NanoCPUs  int64 `json:"NanoCpus"` // CPU quota in units of 10<sup>-9</sup> CPUs. | ||||||
|  |  | ||||||
|  | 	// Applicable to UNIX platforms | ||||||
|  | 	CgroupParent         string // Parent cgroup. | ||||||
|  | 	BlkioWeight          uint16 // Block IO weight (relative weight vs. other containers) | ||||||
|  | 	BlkioWeightDevice    []*blkiodev.WeightDevice | ||||||
|  | 	BlkioDeviceReadBps   []*blkiodev.ThrottleDevice | ||||||
|  | 	BlkioDeviceWriteBps  []*blkiodev.ThrottleDevice | ||||||
|  | 	BlkioDeviceReadIOps  []*blkiodev.ThrottleDevice | ||||||
|  | 	BlkioDeviceWriteIOps []*blkiodev.ThrottleDevice | ||||||
|  | 	CPUPeriod            int64           `json:"CpuPeriod"`          // CPU CFS (Completely Fair Scheduler) period | ||||||
|  | 	CPUQuota             int64           `json:"CpuQuota"`           // CPU CFS (Completely Fair Scheduler) quota | ||||||
|  | 	CPURealtimePeriod    int64           `json:"CpuRealtimePeriod"`  // CPU real-time period | ||||||
|  | 	CPURealtimeRuntime   int64           `json:"CpuRealtimeRuntime"` // CPU real-time runtime | ||||||
|  | 	CpusetCpus           string          // CpusetCpus 0-2, 0,1 | ||||||
|  | 	CpusetMems           string          // CpusetMems 0-2, 0,1 | ||||||
|  | 	Devices              []DeviceMapping // List of devices to map inside the container | ||||||
|  | 	DeviceCgroupRules    []string        // List of rule to be added to the device cgroup | ||||||
|  | 	DeviceRequests       []DeviceRequest // List of device requests for device drivers | ||||||
|  | 	DiskQuota            int64           // Disk limit (in bytes) | ||||||
|  | 	KernelMemory         int64           // Kernel memory limit (in bytes) | ||||||
|  | 	KernelMemoryTCP      int64           // Hard limit for kernel TCP buffer memory (in bytes) | ||||||
|  | 	MemoryReservation    int64           // Memory soft limit (in bytes) | ||||||
|  | 	MemorySwap           int64           // Total memory usage (memory + swap); set `-1` to enable unlimited swap | ||||||
|  | 	MemorySwappiness     *int64          // Tuning container memory swappiness behaviour | ||||||
|  | 	OomKillDisable       *bool           // Whether to disable OOM Killer or not | ||||||
|  | 	PidsLimit            *int64          // Setting PIDs limit for a container; Set `0` or `-1` for unlimited, or `null` to not change. | ||||||
|  | 	Ulimits              []*units.Ulimit // List of ulimits to be set in the container | ||||||
|  |  | ||||||
|  | 	// Applicable to Windows | ||||||
|  | 	CPUCount           int64  `json:"CpuCount"`   // CPU count | ||||||
|  | 	CPUPercent         int64  `json:"CpuPercent"` // CPU percent | ||||||
|  | 	IOMaximumIOps      uint64 // Maximum IOps for the container system drive | ||||||
|  | 	IOMaximumBandwidth uint64 // Maximum IO in bytes per second for the container system drive | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // UpdateConfig holds the mutable attributes of a Container. | ||||||
|  | // Those attributes can be updated at runtime. | ||||||
|  | type UpdateConfig struct { | ||||||
|  | 	// Contains container's resources (cgroups, ulimits) | ||||||
|  | 	Resources | ||||||
|  | 	RestartPolicy RestartPolicy | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // HostConfig the non-portable Config structure of a container. | ||||||
|  | // Here, "non-portable" means "dependent of the host we are running on". | ||||||
|  | // Portable information *should* appear in Config. | ||||||
|  | type HostConfig struct { | ||||||
|  | 	// Applicable to all platforms | ||||||
|  | 	Binds           []string      // List of volume bindings for this container | ||||||
|  | 	ContainerIDFile string        // File (path) where the containerId is written | ||||||
|  | 	LogConfig       LogConfig     // Configuration of the logs for this container | ||||||
|  | 	NetworkMode     NetworkMode   // Network mode to use for the container | ||||||
|  | 	PortBindings    nat.PortMap   // Port mapping between the exposed port (container) and the host | ||||||
|  | 	RestartPolicy   RestartPolicy // Restart policy to be used for the container | ||||||
|  | 	AutoRemove      bool          // Automatically remove container when it exits | ||||||
|  | 	VolumeDriver    string        // Name of the volume driver used to mount volumes | ||||||
|  | 	VolumesFrom     []string      // List of volumes to take from other container | ||||||
|  |  | ||||||
|  | 	// Applicable to UNIX platforms | ||||||
|  | 	CapAdd          strslice.StrSlice // List of kernel capabilities to add to the container | ||||||
|  | 	CapDrop         strslice.StrSlice // List of kernel capabilities to remove from the container | ||||||
|  | 	Capabilities    []string          `json:"Capabilities"` // List of kernel capabilities to be available for container (this overrides the default set) | ||||||
|  | 	DNS             []string          `json:"Dns"`          // List of DNS server to lookup | ||||||
|  | 	DNSOptions      []string          `json:"DnsOptions"`   // List of DNSOption to look for | ||||||
|  | 	DNSSearch       []string          `json:"DnsSearch"`    // List of DNSSearch to look for | ||||||
|  | 	ExtraHosts      []string          // List of extra hosts | ||||||
|  | 	GroupAdd        []string          // List of additional groups that the container process will run as | ||||||
|  | 	IpcMode         IpcMode           // IPC namespace to use for the container | ||||||
|  | 	Cgroup          CgroupSpec        // Cgroup to use for the container | ||||||
|  | 	Links           []string          // List of links (in the name:alias form) | ||||||
|  | 	OomScoreAdj     int               // Container preference for OOM-killing | ||||||
|  | 	PidMode         PidMode           // PID namespace to use for the container | ||||||
|  | 	Privileged      bool              // Is the container in privileged mode | ||||||
|  | 	PublishAllPorts bool              // Should docker publish all exposed port for the container | ||||||
|  | 	ReadonlyRootfs  bool              // Is the container root filesystem in read-only | ||||||
|  | 	SecurityOpt     []string          // List of string values to customize labels for MLS systems, such as SELinux. | ||||||
|  | 	StorageOpt      map[string]string `json:",omitempty"` // Storage driver options per container. | ||||||
|  | 	Tmpfs           map[string]string `json:",omitempty"` // List of tmpfs (mounts) used for the container | ||||||
|  | 	UTSMode         UTSMode           // UTS namespace to use for the container | ||||||
|  | 	UsernsMode      UsernsMode        // The user namespace to use for the container | ||||||
|  | 	ShmSize         int64             // Total shm memory usage | ||||||
|  | 	Sysctls         map[string]string `json:",omitempty"` // List of Namespaced sysctls used for the container | ||||||
|  | 	Runtime         string            `json:",omitempty"` // Runtime to use with this container | ||||||
|  |  | ||||||
|  | 	// Applicable to Windows | ||||||
|  | 	ConsoleSize [2]uint   // Initial console size (height,width) | ||||||
|  | 	Isolation   Isolation // Isolation technology of the container (e.g. default, hyperv) | ||||||
|  |  | ||||||
|  | 	// Contains container's resources (cgroups, ulimits) | ||||||
|  | 	Resources | ||||||
|  |  | ||||||
|  | 	// Mounts specs used by the container | ||||||
|  | 	Mounts []mount.Mount `json:",omitempty"` | ||||||
|  |  | ||||||
|  | 	// MaskedPaths is the list of paths to be masked inside the container (this overrides the default set of paths) | ||||||
|  | 	MaskedPaths []string | ||||||
|  |  | ||||||
|  | 	// ReadonlyPaths is the list of paths to be set as read-only inside the container (this overrides the default set of paths) | ||||||
|  | 	ReadonlyPaths []string | ||||||
|  |  | ||||||
|  | 	// Run a custom init inside the container, if null, use the daemon's configured settings | ||||||
|  | 	Init *bool `json:",omitempty"` | ||||||
|  | } | ||||||
							
								
								
									
										41
									
								
								vendor/github.com/docker/docker/api/types/container/hostconfig_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								vendor/github.com/docker/docker/api/types/container/hostconfig_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | |||||||
|  | // +build !windows | ||||||
|  |  | ||||||
|  | package container // import "github.com/docker/docker/api/types/container" | ||||||
|  |  | ||||||
|  | // IsValid indicates if an isolation technology is valid | ||||||
|  | func (i Isolation) IsValid() bool { | ||||||
|  | 	return i.IsDefault() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // NetworkName returns the name of the network stack. | ||||||
|  | func (n NetworkMode) NetworkName() string { | ||||||
|  | 	if n.IsBridge() { | ||||||
|  | 		return "bridge" | ||||||
|  | 	} else if n.IsHost() { | ||||||
|  | 		return "host" | ||||||
|  | 	} else if n.IsContainer() { | ||||||
|  | 		return "container" | ||||||
|  | 	} else if n.IsNone() { | ||||||
|  | 		return "none" | ||||||
|  | 	} else if n.IsDefault() { | ||||||
|  | 		return "default" | ||||||
|  | 	} else if n.IsUserDefined() { | ||||||
|  | 		return n.UserDefined() | ||||||
|  | 	} | ||||||
|  | 	return "" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // IsBridge indicates whether container uses the bridge network stack | ||||||
|  | func (n NetworkMode) IsBridge() bool { | ||||||
|  | 	return n == "bridge" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // IsHost indicates whether container uses the host network stack. | ||||||
|  | func (n NetworkMode) IsHost() bool { | ||||||
|  | 	return n == "host" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // IsUserDefined indicates user-created network | ||||||
|  | func (n NetworkMode) IsUserDefined() bool { | ||||||
|  | 	return !n.IsDefault() && !n.IsBridge() && !n.IsHost() && !n.IsNone() && !n.IsContainer() | ||||||
|  | } | ||||||
							
								
								
									
										40
									
								
								vendor/github.com/docker/docker/api/types/container/hostconfig_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								vendor/github.com/docker/docker/api/types/container/hostconfig_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | |||||||
|  | package container // import "github.com/docker/docker/api/types/container" | ||||||
|  |  | ||||||
|  | // IsBridge indicates whether container uses the bridge network stack | ||||||
|  | // in windows it is given the name NAT | ||||||
|  | func (n NetworkMode) IsBridge() bool { | ||||||
|  | 	return n == "nat" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // IsHost indicates whether container uses the host network stack. | ||||||
|  | // returns false as this is not supported by windows | ||||||
|  | func (n NetworkMode) IsHost() bool { | ||||||
|  | 	return false | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // IsUserDefined indicates user-created network | ||||||
|  | func (n NetworkMode) IsUserDefined() bool { | ||||||
|  | 	return !n.IsDefault() && !n.IsNone() && !n.IsBridge() && !n.IsContainer() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // IsValid indicates if an isolation technology is valid | ||||||
|  | func (i Isolation) IsValid() bool { | ||||||
|  | 	return i.IsDefault() || i.IsHyperV() || i.IsProcess() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // NetworkName returns the name of the network stack. | ||||||
|  | func (n NetworkMode) NetworkName() string { | ||||||
|  | 	if n.IsDefault() { | ||||||
|  | 		return "default" | ||||||
|  | 	} else if n.IsBridge() { | ||||||
|  | 		return "nat" | ||||||
|  | 	} else if n.IsNone() { | ||||||
|  | 		return "none" | ||||||
|  | 	} else if n.IsContainer() { | ||||||
|  | 		return "container" | ||||||
|  | 	} else if n.IsUserDefined() { | ||||||
|  | 		return n.UserDefined() | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return "" | ||||||
|  | } | ||||||
							
								
								
									
										22
									
								
								vendor/github.com/docker/docker/api/types/container/waitcondition.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								vendor/github.com/docker/docker/api/types/container/waitcondition.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | |||||||
|  | package container // import "github.com/docker/docker/api/types/container" | ||||||
|  |  | ||||||
|  | // WaitCondition is a type used to specify a container state for which | ||||||
|  | // to wait. | ||||||
|  | type WaitCondition string | ||||||
|  |  | ||||||
|  | // Possible WaitCondition Values. | ||||||
|  | // | ||||||
|  | // WaitConditionNotRunning (default) is used to wait for any of the non-running | ||||||
|  | // states: "created", "exited", "dead", "removing", or "removed". | ||||||
|  | // | ||||||
|  | // WaitConditionNextExit is used to wait for the next time the state changes | ||||||
|  | // to a non-running state. If the state is currently "created" or "exited", | ||||||
|  | // this would cause Wait() to block until either the container runs and exits | ||||||
|  | // or is removed. | ||||||
|  | // | ||||||
|  | // WaitConditionRemoved is used to wait for the container to be removed. | ||||||
|  | const ( | ||||||
|  | 	WaitConditionNotRunning WaitCondition = "not-running" | ||||||
|  | 	WaitConditionNextExit   WaitCondition = "next-exit" | ||||||
|  | 	WaitConditionRemoved    WaitCondition = "removed" | ||||||
|  | ) | ||||||
							
								
								
									
										13
									
								
								vendor/github.com/docker/docker/api/types/error_response.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								vendor/github.com/docker/docker/api/types/error_response.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | package types | ||||||
|  |  | ||||||
|  | // This file was generated by the swagger tool. | ||||||
|  | // Editing this file might prove futile when you re-run the swagger generate command | ||||||
|  |  | ||||||
|  | // ErrorResponse Represents an error. | ||||||
|  | // swagger:model ErrorResponse | ||||||
|  | type ErrorResponse struct { | ||||||
|  |  | ||||||
|  | 	// The error message. | ||||||
|  | 	// Required: true | ||||||
|  | 	Message string `json:"message"` | ||||||
|  | } | ||||||
							
								
								
									
										52
									
								
								vendor/github.com/docker/docker/api/types/events/events.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								vendor/github.com/docker/docker/api/types/events/events.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,52 @@ | |||||||
|  | package events // import "github.com/docker/docker/api/types/events" | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	// ContainerEventType is the event type that containers generate | ||||||
|  | 	ContainerEventType = "container" | ||||||
|  | 	// DaemonEventType is the event type that daemon generate | ||||||
|  | 	DaemonEventType = "daemon" | ||||||
|  | 	// ImageEventType is the event type that images generate | ||||||
|  | 	ImageEventType = "image" | ||||||
|  | 	// NetworkEventType is the event type that networks generate | ||||||
|  | 	NetworkEventType = "network" | ||||||
|  | 	// PluginEventType is the event type that plugins generate | ||||||
|  | 	PluginEventType = "plugin" | ||||||
|  | 	// VolumeEventType is the event type that volumes generate | ||||||
|  | 	VolumeEventType = "volume" | ||||||
|  | 	// ServiceEventType is the event type that services generate | ||||||
|  | 	ServiceEventType = "service" | ||||||
|  | 	// NodeEventType is the event type that nodes generate | ||||||
|  | 	NodeEventType = "node" | ||||||
|  | 	// SecretEventType is the event type that secrets generate | ||||||
|  | 	SecretEventType = "secret" | ||||||
|  | 	// ConfigEventType is the event type that configs generate | ||||||
|  | 	ConfigEventType = "config" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // Actor describes something that generates events, | ||||||
|  | // like a container, or a network, or a volume. | ||||||
|  | // It has a defined name and a set or attributes. | ||||||
|  | // The container attributes are its labels, other actors | ||||||
|  | // can generate these attributes from other properties. | ||||||
|  | type Actor struct { | ||||||
|  | 	ID         string | ||||||
|  | 	Attributes map[string]string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Message represents the information an event contains | ||||||
|  | type Message struct { | ||||||
|  | 	// Deprecated information from JSONMessage. | ||||||
|  | 	// With data only in container events. | ||||||
|  | 	Status string `json:"status,omitempty"` | ||||||
|  | 	ID     string `json:"id,omitempty"` | ||||||
|  | 	From   string `json:"from,omitempty"` | ||||||
|  |  | ||||||
|  | 	Type   string | ||||||
|  | 	Action string | ||||||
|  | 	Actor  Actor | ||||||
|  | 	// Engine events are local scope. Cluster events are swarm scope. | ||||||
|  | 	Scope string `json:"scope,omitempty"` | ||||||
|  |  | ||||||
|  | 	Time     int64 `json:"time,omitempty"` | ||||||
|  | 	TimeNano int64 `json:"timeNano,omitempty"` | ||||||
|  | } | ||||||
							
								
								
									
										315
									
								
								vendor/github.com/docker/docker/api/types/filters/parse.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										315
									
								
								vendor/github.com/docker/docker/api/types/filters/parse.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,315 @@ | |||||||
|  | /*Package filters provides tools for encoding a mapping of keys to a set of | ||||||
|  | multiple values. | ||||||
|  | */ | ||||||
|  | package filters // import "github.com/docker/docker/api/types/filters" | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"encoding/json" | ||||||
|  | 	"regexp" | ||||||
|  | 	"strings" | ||||||
|  |  | ||||||
|  | 	"github.com/docker/docker/api/types/versions" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // Args stores a mapping of keys to a set of multiple values. | ||||||
|  | type Args struct { | ||||||
|  | 	fields map[string]map[string]bool | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // KeyValuePair are used to initialize a new Args | ||||||
|  | type KeyValuePair struct { | ||||||
|  | 	Key   string | ||||||
|  | 	Value string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Arg creates a new KeyValuePair for initializing Args | ||||||
|  | func Arg(key, value string) KeyValuePair { | ||||||
|  | 	return KeyValuePair{Key: key, Value: value} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // NewArgs returns a new Args populated with the initial args | ||||||
|  | func NewArgs(initialArgs ...KeyValuePair) Args { | ||||||
|  | 	args := Args{fields: map[string]map[string]bool{}} | ||||||
|  | 	for _, arg := range initialArgs { | ||||||
|  | 		args.Add(arg.Key, arg.Value) | ||||||
|  | 	} | ||||||
|  | 	return args | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // MarshalJSON returns a JSON byte representation of the Args | ||||||
|  | func (args Args) MarshalJSON() ([]byte, error) { | ||||||
|  | 	if len(args.fields) == 0 { | ||||||
|  | 		return []byte{}, nil | ||||||
|  | 	} | ||||||
|  | 	return json.Marshal(args.fields) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ToJSON returns the Args as a JSON encoded string | ||||||
|  | func ToJSON(a Args) (string, error) { | ||||||
|  | 	if a.Len() == 0 { | ||||||
|  | 		return "", nil | ||||||
|  | 	} | ||||||
|  | 	buf, err := json.Marshal(a) | ||||||
|  | 	return string(buf), err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ToParamWithVersion encodes Args as a JSON string. If version is less than 1.22 | ||||||
|  | // then the encoded format will use an older legacy format where the values are a | ||||||
|  | // list of strings, instead of a set. | ||||||
|  | // | ||||||
|  | // Deprecated: Use ToJSON | ||||||
|  | func ToParamWithVersion(version string, a Args) (string, error) { | ||||||
|  | 	if a.Len() == 0 { | ||||||
|  | 		return "", nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if version != "" && versions.LessThan(version, "1.22") { | ||||||
|  | 		buf, err := json.Marshal(convertArgsToSlice(a.fields)) | ||||||
|  | 		return string(buf), err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return ToJSON(a) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // FromJSON decodes a JSON encoded string into Args | ||||||
|  | func FromJSON(p string) (Args, error) { | ||||||
|  | 	args := NewArgs() | ||||||
|  |  | ||||||
|  | 	if p == "" { | ||||||
|  | 		return args, nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	raw := []byte(p) | ||||||
|  | 	err := json.Unmarshal(raw, &args) | ||||||
|  | 	if err == nil { | ||||||
|  | 		return args, nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Fallback to parsing arguments in the legacy slice format | ||||||
|  | 	deprecated := map[string][]string{} | ||||||
|  | 	if legacyErr := json.Unmarshal(raw, &deprecated); legacyErr != nil { | ||||||
|  | 		return args, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	args.fields = deprecatedArgs(deprecated) | ||||||
|  | 	return args, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // UnmarshalJSON populates the Args from JSON encode bytes | ||||||
|  | func (args Args) UnmarshalJSON(raw []byte) error { | ||||||
|  | 	if len(raw) == 0 { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 	return json.Unmarshal(raw, &args.fields) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Get returns the list of values associated with the key | ||||||
|  | func (args Args) Get(key string) []string { | ||||||
|  | 	values := args.fields[key] | ||||||
|  | 	if values == nil { | ||||||
|  | 		return make([]string, 0) | ||||||
|  | 	} | ||||||
|  | 	slice := make([]string, 0, len(values)) | ||||||
|  | 	for key := range values { | ||||||
|  | 		slice = append(slice, key) | ||||||
|  | 	} | ||||||
|  | 	return slice | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Add a new value to the set of values | ||||||
|  | func (args Args) Add(key, value string) { | ||||||
|  | 	if _, ok := args.fields[key]; ok { | ||||||
|  | 		args.fields[key][value] = true | ||||||
|  | 	} else { | ||||||
|  | 		args.fields[key] = map[string]bool{value: true} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Del removes a value from the set | ||||||
|  | func (args Args) Del(key, value string) { | ||||||
|  | 	if _, ok := args.fields[key]; ok { | ||||||
|  | 		delete(args.fields[key], value) | ||||||
|  | 		if len(args.fields[key]) == 0 { | ||||||
|  | 			delete(args.fields, key) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Len returns the number of keys in the mapping | ||||||
|  | func (args Args) Len() int { | ||||||
|  | 	return len(args.fields) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // MatchKVList returns true if all the pairs in sources exist as key=value | ||||||
|  | // pairs in the mapping at key, or if there are no values at key. | ||||||
|  | func (args Args) MatchKVList(key string, sources map[string]string) bool { | ||||||
|  | 	fieldValues := args.fields[key] | ||||||
|  |  | ||||||
|  | 	//do not filter if there is no filter set or cannot determine filter | ||||||
|  | 	if len(fieldValues) == 0 { | ||||||
|  | 		return true | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if len(sources) == 0 { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	for value := range fieldValues { | ||||||
|  | 		testKV := strings.SplitN(value, "=", 2) | ||||||
|  |  | ||||||
|  | 		v, ok := sources[testKV[0]] | ||||||
|  | 		if !ok { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 		if len(testKV) == 2 && testKV[1] != v { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return true | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Match returns true if any of the values at key match the source string | ||||||
|  | func (args Args) Match(field, source string) bool { | ||||||
|  | 	if args.ExactMatch(field, source) { | ||||||
|  | 		return true | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	fieldValues := args.fields[field] | ||||||
|  | 	for name2match := range fieldValues { | ||||||
|  | 		match, err := regexp.MatchString(name2match, source) | ||||||
|  | 		if err != nil { | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		if match { | ||||||
|  | 			return true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return false | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ExactMatch returns true if the source matches exactly one of the values. | ||||||
|  | func (args Args) ExactMatch(key, source string) bool { | ||||||
|  | 	fieldValues, ok := args.fields[key] | ||||||
|  | 	//do not filter if there is no filter set or cannot determine filter | ||||||
|  | 	if !ok || len(fieldValues) == 0 { | ||||||
|  | 		return true | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// try to match full name value to avoid O(N) regular expression matching | ||||||
|  | 	return fieldValues[source] | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // UniqueExactMatch returns true if there is only one value and the source | ||||||
|  | // matches exactly the value. | ||||||
|  | func (args Args) UniqueExactMatch(key, source string) bool { | ||||||
|  | 	fieldValues := args.fields[key] | ||||||
|  | 	//do not filter if there is no filter set or cannot determine filter | ||||||
|  | 	if len(fieldValues) == 0 { | ||||||
|  | 		return true | ||||||
|  | 	} | ||||||
|  | 	if len(args.fields[key]) != 1 { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// try to match full name value to avoid O(N) regular expression matching | ||||||
|  | 	return fieldValues[source] | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // FuzzyMatch returns true if the source matches exactly one value,  or the | ||||||
|  | // source has one of the values as a prefix. | ||||||
|  | func (args Args) FuzzyMatch(key, source string) bool { | ||||||
|  | 	if args.ExactMatch(key, source) { | ||||||
|  | 		return true | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	fieldValues := args.fields[key] | ||||||
|  | 	for prefix := range fieldValues { | ||||||
|  | 		if strings.HasPrefix(source, prefix) { | ||||||
|  | 			return true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return false | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Contains returns true if the key exists in the mapping | ||||||
|  | func (args Args) Contains(field string) bool { | ||||||
|  | 	_, ok := args.fields[field] | ||||||
|  | 	return ok | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type invalidFilter string | ||||||
|  |  | ||||||
|  | func (e invalidFilter) Error() string { | ||||||
|  | 	return "Invalid filter '" + string(e) + "'" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (invalidFilter) InvalidParameter() {} | ||||||
|  |  | ||||||
|  | // Validate compared the set of accepted keys against the keys in the mapping. | ||||||
|  | // An error is returned if any mapping keys are not in the accepted set. | ||||||
|  | func (args Args) Validate(accepted map[string]bool) error { | ||||||
|  | 	for name := range args.fields { | ||||||
|  | 		if !accepted[name] { | ||||||
|  | 			return invalidFilter(name) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // WalkValues iterates over the list of values for a key in the mapping and calls | ||||||
|  | // op() for each value. If op returns an error the iteration stops and the | ||||||
|  | // error is returned. | ||||||
|  | func (args Args) WalkValues(field string, op func(value string) error) error { | ||||||
|  | 	if _, ok := args.fields[field]; !ok { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 	for v := range args.fields[field] { | ||||||
|  | 		if err := op(v); err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Clone returns a copy of args. | ||||||
|  | func (args Args) Clone() (newArgs Args) { | ||||||
|  | 	newArgs.fields = make(map[string]map[string]bool, len(args.fields)) | ||||||
|  | 	for k, m := range args.fields { | ||||||
|  | 		var mm map[string]bool | ||||||
|  | 		if m != nil { | ||||||
|  | 			mm = make(map[string]bool, len(m)) | ||||||
|  | 			for kk, v := range m { | ||||||
|  | 				mm[kk] = v | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		newArgs.fields[k] = mm | ||||||
|  | 	} | ||||||
|  | 	return newArgs | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func deprecatedArgs(d map[string][]string) map[string]map[string]bool { | ||||||
|  | 	m := map[string]map[string]bool{} | ||||||
|  | 	for k, v := range d { | ||||||
|  | 		values := map[string]bool{} | ||||||
|  | 		for _, vv := range v { | ||||||
|  | 			values[vv] = true | ||||||
|  | 		} | ||||||
|  | 		m[k] = values | ||||||
|  | 	} | ||||||
|  | 	return m | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func convertArgsToSlice(f map[string]map[string]bool) map[string][]string { | ||||||
|  | 	m := map[string][]string{} | ||||||
|  | 	for k, v := range f { | ||||||
|  | 		values := []string{} | ||||||
|  | 		for kk := range v { | ||||||
|  | 			if v[kk] { | ||||||
|  | 				values = append(values, kk) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		m[k] = values | ||||||
|  | 	} | ||||||
|  | 	return m | ||||||
|  | } | ||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user