├── demo.gif ├── go.mod ├── go.sum ├── .github └── workflows │ └── release.yml ├── README.zh.md ├── LICENSE ├── README.md ├── .gitignore ├── main.go ├── update_metadata.proto └── update_metadata.pb.go /demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tobyxdd/android-ota-payload-extractor/HEAD/demo.gif -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/tobyxdd/android-ota-payload-extractor 2 | 3 | go 1.13 4 | 5 | require ( 6 | github.com/golang/protobuf v1.3.4 7 | github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 8 | ) 9 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/golang/protobuf v1.3.4 h1:87PNWwrRvUSnqS4dlcBU/ftvOIBep4sYuBLlh6rX2wk= 2 | github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 3 | github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo= 4 | github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= 5 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | release: 5 | types: [ created ] 6 | 7 | jobs: 8 | releases-matrix: 9 | name: Release Go Binary 10 | runs-on: ubuntu-latest 11 | strategy: 12 | matrix: 13 | goos: [ linux, darwin, windows ] 14 | goarch: [ amd64, arm64 ] 15 | steps: 16 | - uses: actions/checkout@v3 17 | - uses: wangyoucao577/go-release-action@v1.25 18 | with: 19 | github_token: ${{ secrets.GITHUB_TOKEN }} 20 | goos: ${{ matrix.goos }} 21 | goarch: ${{ matrix.goarch }} 22 | goversion: "https://dl.google.com/go/go1.17.8.linux-amd64.tar.gz" 23 | project_path: "." 24 | binary_name: "android-ota-extractor" 25 | ldflags: "-s -w" 26 | md5sum: false 27 | sha256sum: true 28 | -------------------------------------------------------------------------------- /README.zh.md: -------------------------------------------------------------------------------- 1 | # Android OTA 镜像解压工具 2 | 3 | Go 编写的 Android OTA 镜像解压工具 4 | 5 | [下载](https://github.com/tobyxdd/android-ota-payload-extractor/releases) 6 | 7 | ## 使用方法 8 | 9 | ### 命令行 10 | 11 | ``` 12 | ./android-ota-payload-extractor [(optional) file to extract 1] [(optional) file to extract 2] ... 13 | ``` 14 | 15 | 样例(从 raven-ota.zip 解压 boot 和 vendor): 16 | 17 | ``` 18 | ./android-ota-payload-extractor.exe raven-ota.zip boot vendor 19 | ``` 20 | 21 | 支持单独解压出来的 payload.bin,也支持直接用整个 ROM zip 包。 22 | 23 | 如果没有指定要解压的文件,默认会解压 payload 中包含的所有文件。 24 | 25 | ![Demo GIF](demo.gif) 26 | 27 | ## About 28 | 29 | 灵感基于: https://github.com/cyxx/extract_android_ota_payload 30 | 31 | 从 Android OTA 解包镜像文件有很多用途。例如对于没有 TWRP 设备,想要刷 Magisk 就需要拿到 ROM 的 boot.img 打补丁后刷回去。但此前 Python 编写的提取工具需要配置 Python 环境,对于没经验的 Windows 用户来说比较复杂。 32 | 33 | 本项目是一个性能更高的跨平台镜像解压工具,无需安装配置任何第三方依赖。将 payload 或 zip 拖到程序上即可。 -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Toby 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Android OTA Payload Extractor 2 | 3 | Android OTA payload extractor written in Go. 4 | 5 | [Download](https://github.com/tobyxdd/android-ota-payload-extractor/releases) 6 | 7 | [中文](README.zh.md) 8 | 9 | ## Usage 10 | 11 | ``` 12 | ./android-ota-payload-extractor [(optional) file to extract 1] [(optional) file to extract 2] ... 13 | ``` 14 | 15 | Example (extract boot and vendor images from raven-ota.zip): 16 | 17 | ``` 18 | ./android-ota-payload-extractor.exe raven-ota.zip boot vendor 19 | ``` 20 | 21 | It can parse `payload.bin` directly, or automatically extract from OTA zip files. 22 | 23 | When files to extract are not specified, it will extract all files in the payload. 24 | 25 | ![Demo GIF](demo.gif) 26 | 27 | ## About 28 | 29 | Inspired by https://github.com/cyxx/extract_android_ota_payload. 30 | 31 | Extracting images from Android OTA packages is very useful for various purposes. For example, patching the boot 32 | image to install Magisk without TWRP. However, using the above Python script is often a pain in the ass because of 33 | Python and its dependencies, especially for inexperienced Windows users. 34 | 35 | This project aims to provide everyone with a faster & cross-platform Android OTA payload extractor that's much easier to 36 | use - just drag and drop the ROM file onto the program. -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/go,linux,macos,windows,intellij+all 3 | # Edit at https://www.gitignore.io/?templates=go,linux,macos,windows,intellij+all 4 | 5 | ### Go ### 6 | # Binaries for programs and plugins 7 | *.exe 8 | *.exe~ 9 | *.dll 10 | *.so 11 | *.dylib 12 | 13 | # Test binary, built with `go test -c` 14 | *.test 15 | 16 | # Output of the go coverage tool, specifically when used with LiteIDE 17 | *.out 18 | 19 | # Dependency directories (remove the comment below to include it) 20 | # vendor/ 21 | 22 | ### Go Patch ### 23 | /vendor/ 24 | /Godeps/ 25 | 26 | ### Intellij+all ### 27 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm 28 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 29 | 30 | # User-specific stuff 31 | .idea/**/workspace.xml 32 | .idea/**/tasks.xml 33 | .idea/**/usage.statistics.xml 34 | .idea/**/dictionaries 35 | .idea/**/shelf 36 | 37 | # Generated files 38 | .idea/**/contentModel.xml 39 | 40 | # Sensitive or high-churn files 41 | .idea/**/dataSources/ 42 | .idea/**/dataSources.ids 43 | .idea/**/dataSources.local.xml 44 | .idea/**/sqlDataSources.xml 45 | .idea/**/dynamic.xml 46 | .idea/**/uiDesigner.xml 47 | .idea/**/dbnavigator.xml 48 | 49 | # Gradle 50 | .idea/**/gradle.xml 51 | .idea/**/libraries 52 | 53 | # Gradle and Maven with auto-import 54 | # When using Gradle or Maven with auto-import, you should exclude module files, 55 | # since they will be recreated, and may cause churn. Uncomment if using 56 | # auto-import. 57 | # .idea/modules.xml 58 | # .idea/*.iml 59 | # .idea/modules 60 | # *.iml 61 | # *.ipr 62 | 63 | # CMake 64 | cmake-build-*/ 65 | 66 | # Mongo Explorer plugin 67 | .idea/**/mongoSettings.xml 68 | 69 | # File-based project format 70 | *.iws 71 | 72 | # IntelliJ 73 | out/ 74 | 75 | # mpeltonen/sbt-idea plugin 76 | .idea_modules/ 77 | 78 | # JIRA plugin 79 | atlassian-ide-plugin.xml 80 | 81 | # Cursive Clojure plugin 82 | .idea/replstate.xml 83 | 84 | # Crashlytics plugin (for Android Studio and IntelliJ) 85 | com_crashlytics_export_strings.xml 86 | crashlytics.properties 87 | crashlytics-build.properties 88 | fabric.properties 89 | 90 | # Editor-based Rest Client 91 | .idea/httpRequests 92 | 93 | # Android studio 3.1+ serialized cache file 94 | .idea/caches/build_file_checksums.ser 95 | 96 | ### Intellij+all Patch ### 97 | # Ignores the whole .idea folder and all .iml files 98 | # See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360 99 | 100 | .idea/ 101 | 102 | # Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023 103 | 104 | *.iml 105 | modules.xml 106 | .idea/misc.xml 107 | *.ipr 108 | 109 | # Sonarlint plugin 110 | .idea/sonarlint 111 | 112 | ### Linux ### 113 | *~ 114 | 115 | # temporary files which can be created if a process still has a handle open of a deleted file 116 | .fuse_hidden* 117 | 118 | # KDE directory preferences 119 | .directory 120 | 121 | # Linux trash folder which might appear on any partition or disk 122 | .Trash-* 123 | 124 | # .nfs files are created when an open file is removed but is still being accessed 125 | .nfs* 126 | 127 | ### macOS ### 128 | # General 129 | .DS_Store 130 | .AppleDouble 131 | .LSOverride 132 | 133 | # Icon must end with two \r 134 | Icon 135 | 136 | # Thumbnails 137 | ._* 138 | 139 | # Files that might appear in the root of a volume 140 | .DocumentRevisions-V100 141 | .fseventsd 142 | .Spotlight-V100 143 | .TemporaryItems 144 | .Trashes 145 | .VolumeIcon.icns 146 | .com.apple.timemachine.donotpresent 147 | 148 | # Directories potentially created on remote AFP share 149 | .AppleDB 150 | .AppleDesktop 151 | Network Trash Folder 152 | Temporary Items 153 | .apdisk 154 | 155 | ### Windows ### 156 | # Windows thumbnail cache files 157 | Thumbs.db 158 | Thumbs.db:encryptable 159 | ehthumbs.db 160 | ehthumbs_vista.db 161 | 162 | # Dump file 163 | *.stackdump 164 | 165 | # Folder config file 166 | [Dd]esktop.ini 167 | 168 | # Recycle Bin used on file shares 169 | $RECYCLE.BIN/ 170 | 171 | # Windows Installer files 172 | *.cab 173 | *.msi 174 | *.msix 175 | *.msm 176 | *.msp 177 | 178 | # Windows shortcuts 179 | *.lnk 180 | 181 | # End of https://www.gitignore.io/api/go,linux,macos,windows,intellij+all -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "archive/zip" 5 | "bytes" 6 | "compress/bzip2" 7 | "encoding/binary" 8 | "fmt" 9 | "io" 10 | "log" 11 | "os" 12 | 13 | "github.com/golang/protobuf/proto" 14 | "github.com/xi2/xz" 15 | ) 16 | 17 | const ( 18 | payloadFilename = "payload.bin" 19 | 20 | zipMagic = "PK" 21 | payloadMagic = "CrAU" 22 | 23 | brilloMajorPayloadVersion = 2 24 | ) 25 | 26 | func main() { 27 | if len(os.Args) < 2 { 28 | fmt.Printf("Usage: %s [(optional) file to extract...]\n", os.Args[0]) 29 | os.Exit(1) 30 | } 31 | filename := os.Args[1] 32 | extractFiles := os.Args[2:] 33 | f, err := os.Open(filename) 34 | if err != nil { 35 | log.Fatalf("Failed to open file: %s", err) 36 | } 37 | if isZip(f) { 38 | // Extract payload.bin from the zip first 39 | _ = f.Close() 40 | log.Printf("Input is a zip file, searching for %s ...\n", payloadFilename) 41 | zr, err := zip.OpenReader(filename) 42 | if err != nil { 43 | log.Fatalf("Failed to open the zip file: %s\n", err.Error()) 44 | } 45 | zf, err := findPayload(zr) 46 | if err != nil { 47 | log.Fatalf("Failed to read from the zip file: %s\n", err.Error()) 48 | } 49 | if zf == nil { 50 | log.Fatalf("%s not found in the zip file\n", payloadFilename) 51 | } 52 | log.Printf("Extracting %s ...\n", payloadFilename) 53 | f, err = os.Create(payloadFilename) 54 | if err != nil { 55 | log.Fatalf("Failed to create the extraction file: %s\n", err.Error()) 56 | } 57 | _, err = io.Copy(f, zf) 58 | if err != nil { 59 | log.Fatalf("Failed to extract: %s\n", err.Error()) 60 | } 61 | _ = zf.Close() 62 | _ = zr.Close() 63 | _, _ = f.Seek(0, 0) 64 | } 65 | parsePayload(f, extractFiles) 66 | } 67 | 68 | func isZip(f *os.File) bool { 69 | header := make([]byte, len(zipMagic)) 70 | _, err := f.Read(header) 71 | _, _ = f.Seek(0, 0) 72 | return err == nil && string(header) == zipMagic 73 | } 74 | 75 | func findPayload(zr *zip.ReadCloser) (io.ReadCloser, error) { 76 | for _, f := range zr.File { 77 | if f.Name == payloadFilename { 78 | return f.Open() 79 | } 80 | } 81 | return nil, nil 82 | } 83 | 84 | func parsePayload(r io.ReadSeeker, extractFiles []string) { 85 | log.Println("Parsing payload...") 86 | // magic 87 | magic := make([]byte, len(payloadMagic)) 88 | _, err := r.Read(magic) 89 | if err != nil || string(magic) != payloadMagic { 90 | log.Fatalf("Incorrect magic (%s)\n", string(magic)) 91 | } 92 | // version & lengths 93 | var version, manifestLen uint64 94 | var metadataSigLen uint32 95 | err = binary.Read(r, binary.BigEndian, &version) 96 | if err != nil || version != brilloMajorPayloadVersion { 97 | log.Fatalf("Unsupported payload version (%d). This tool only supports version %d\n", 98 | version, brilloMajorPayloadVersion) 99 | } 100 | err = binary.Read(r, binary.BigEndian, &manifestLen) 101 | if err != nil || !(manifestLen > 0) { 102 | log.Fatalf("Incorrect manifest length (%d)\n", manifestLen) 103 | } 104 | err = binary.Read(r, binary.BigEndian, &metadataSigLen) 105 | if err != nil || !(metadataSigLen > 0) { 106 | log.Fatalf("Incorrect metadata signature length (%d)\n", metadataSigLen) 107 | } 108 | // manifest 109 | manifestRaw := make([]byte, manifestLen) 110 | n, err := r.Read(manifestRaw) 111 | if err != nil || uint64(n) != manifestLen { 112 | log.Fatalf("Failed to read the manifest (%d)\n", manifestLen) 113 | } 114 | var manifest DeltaArchiveManifest 115 | err = proto.Unmarshal(manifestRaw, &manifest) 116 | if err != nil { 117 | log.Fatalf("Failed to parse the manifest: %s\n", err.Error()) 118 | } 119 | // only support full payloads! 120 | if *manifest.MinorVersion != 0 { 121 | log.Fatalf("Delta payloads are not supported, please use a full payload file\n") 122 | } 123 | // print manifest info 124 | log.Printf("Block size: %d, Partition count: %d\n", 125 | *manifest.BlockSize, len(manifest.Partitions)) 126 | // extract partitions 127 | extractPartitions(&manifest, r, 24+manifestLen+uint64(metadataSigLen), extractFiles) 128 | // done 129 | log.Println("Done!") 130 | } 131 | 132 | func extractPartitions(manifest *DeltaArchiveManifest, r io.ReadSeeker, baseOffset uint64, extractFiles []string) { 133 | for _, p := range manifest.Partitions { 134 | if p.PartitionName == nil || (len(extractFiles) > 0 && !contains(extractFiles, *p.PartitionName)) { 135 | continue 136 | } 137 | log.Printf("Extracting %s (%d ops) ...", *p.PartitionName, len(p.Operations)) 138 | outFilename := fmt.Sprintf("%s.img", *p.PartitionName) 139 | extractPartition(p, outFilename, r, baseOffset, *manifest.BlockSize) 140 | } 141 | } 142 | 143 | func extractPartition(p *PartitionUpdate, outFilename string, r io.ReadSeeker, baseOffset uint64, blockSize uint32) { 144 | outFile, err := os.Create(outFilename) 145 | if err != nil { 146 | log.Fatalf("Failed to create the output file: %s\n", err.Error()) 147 | } 148 | for _, op := range p.Operations { 149 | data, dataPos := make([]byte, *op.DataLength), int64(baseOffset+*op.DataOffset) 150 | 151 | _, err = r.Seek(dataPos, 0) 152 | if err != nil { 153 | _ = outFile.Close() 154 | log.Fatalf("Failed to seek to %d in partition %s: %s\n", dataPos, outFilename, err.Error()) 155 | } 156 | n, err := r.Read(data) 157 | if err != nil || uint64(n) != *op.DataLength { 158 | _ = outFile.Close() 159 | log.Fatalf("Failed to read enough data from partition %s: %s\n", outFilename, err.Error()) 160 | } 161 | 162 | outSeekPos := int64(*op.DstExtents[0].StartBlock * uint64(blockSize)) 163 | _, err = outFile.Seek(outSeekPos, 0) 164 | if err != nil { 165 | _ = outFile.Close() 166 | log.Fatalf("Failed to seek to %d in partition %s: %s\n", outSeekPos, outFilename, err.Error()) 167 | } 168 | 169 | switch *op.Type { 170 | case InstallOperation_REPLACE: 171 | _, err = outFile.Write(data) 172 | if err != nil { 173 | _ = outFile.Close() 174 | log.Fatalf("Failed to write output to %s: %s\n", outFilename, err.Error()) 175 | } 176 | case InstallOperation_REPLACE_BZ: 177 | bzr := bzip2.NewReader(bytes.NewReader(data)) 178 | _, err = io.Copy(outFile, bzr) 179 | if err != nil { 180 | _ = outFile.Close() 181 | log.Fatalf("Failed to write output to %s: %s\n", outFilename, err.Error()) 182 | } 183 | case InstallOperation_REPLACE_XZ: 184 | xzr, err := xz.NewReader(bytes.NewReader(data), 0) 185 | if err != nil { 186 | _ = outFile.Close() 187 | log.Fatalf("Bad xz data in partition %s: %s\n", *p.PartitionName, err.Error()) 188 | } 189 | _, err = io.Copy(outFile, xzr) 190 | if err != nil { 191 | _ = outFile.Close() 192 | log.Fatalf("Failed to write output to %s: %s\n", outFilename, err.Error()) 193 | } 194 | case InstallOperation_ZERO: 195 | for _, ext := range op.DstExtents { 196 | outSeekPos = int64(*ext.StartBlock * uint64(blockSize)) 197 | _, err = outFile.Seek(outSeekPos, 0) 198 | if err != nil { 199 | _ = outFile.Close() 200 | log.Fatalf("Failed to seek to %d in partition %s: %s\n", outSeekPos, outFilename, err.Error()) 201 | } 202 | // write zeros 203 | _, err = io.Copy(outFile, bytes.NewReader(make([]byte, *ext.NumBlocks*uint64(blockSize)))) 204 | if err != nil { 205 | _ = outFile.Close() 206 | log.Fatalf("Failed to write output to %s: %s\n", outFilename, err.Error()) 207 | } 208 | } 209 | default: 210 | _ = outFile.Close() 211 | log.Fatalf("Unsupported operation type: %d (%s), please report a bug\n", 212 | *op.Type, InstallOperation_Type_name[int32(*op.Type)]) 213 | } 214 | } 215 | } 216 | 217 | func contains(ss []string, s string) bool { 218 | for _, v := range ss { 219 | if v == s { 220 | return true 221 | } 222 | } 223 | return false 224 | } 225 | -------------------------------------------------------------------------------- /update_metadata.proto: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2010 The Android Open Source Project 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | // Update file format: An update file contains all the operations needed 17 | // to update a system to a specific version. It can be a full payload which 18 | // can update from any version, or a delta payload which can only update 19 | // from a specific version. 20 | // The update format is represented by this struct pseudocode: 21 | // struct delta_update_file { 22 | // char magic[4] = "CrAU"; 23 | // uint64 file_format_version; // payload major version 24 | // uint64 manifest_size; // Size of protobuf DeltaArchiveManifest 25 | // 26 | // // Only present if format_version >= 2: 27 | // uint32 metadata_signature_size; 28 | // 29 | // // The DeltaArchiveManifest protobuf serialized, not compressed. 30 | // char manifest[manifest_size]; 31 | // 32 | // // The signature of the metadata (from the beginning of the payload up to 33 | // // this location, not including the signature itself). This is a serialized 34 | // // Signatures message. 35 | // char metadata_signature_message[metadata_signature_size]; 36 | // 37 | // // Data blobs for files, no specific format. The specific offset 38 | // // and length of each data blob is recorded in the DeltaArchiveManifest. 39 | // struct { 40 | // char data[]; 41 | // } blobs[]; 42 | // 43 | // // The signature of the entire payload, everything up to this location, 44 | // // except that metadata_signature_message is skipped to simplify signing 45 | // // process. These two are not signed: 46 | // uint64 payload_signatures_message_size; 47 | // // This is a serialized Signatures message. 48 | // char payload_signatures_message[payload_signatures_message_size]; 49 | // 50 | // }; 51 | // The DeltaArchiveManifest protobuf is an ordered list of InstallOperation 52 | // objects. These objects are stored in a linear array in the 53 | // DeltaArchiveManifest. Each operation is applied in order by the client. 54 | // The DeltaArchiveManifest also contains the initial and final 55 | // checksums for the device. 56 | // The client will perform each InstallOperation in order, beginning even 57 | // before the entire delta file is downloaded (but after at least the 58 | // protobuf is downloaded). The types of operations are explained: 59 | // - REPLACE: Replace the dst_extents on the drive with the attached data, 60 | // zero padding out to block size. 61 | // - REPLACE_BZ: bzip2-uncompress the attached data and write it into 62 | // dst_extents on the drive, zero padding to block size. 63 | // - MOVE: Copy the data in src_extents to dst_extents. Extents may overlap, 64 | // so it may be desirable to read all src_extents data into memory before 65 | // writing it out. (deprecated) 66 | // - SOURCE_COPY: Copy the data in src_extents in the old partition to 67 | // dst_extents in the new partition. There's no overlapping of data because 68 | // the extents are in different partitions. 69 | // - BSDIFF: Read src_length bytes from src_extents into memory, perform 70 | // bspatch with attached data, write new data to dst_extents, zero padding 71 | // to block size. (deprecated) 72 | // - SOURCE_BSDIFF: Read the data in src_extents in the old partition, perform 73 | // bspatch with the attached data and write the new data to dst_extents in the 74 | // new partition. 75 | // - ZERO: Write zeros to the destination dst_extents. 76 | // - DISCARD: Discard the destination dst_extents blocks on the physical medium. 77 | // the data read from those block is undefined. 78 | // - REPLACE_XZ: Replace the dst_extents with the contents of the attached 79 | // xz file after decompression. The xz file should only use crc32 or no crc at 80 | // all to be compatible with xz-embedded. 81 | // - PUFFDIFF: Read the data in src_extents in the old partition, perform 82 | // puffpatch with the attached data and write the new data to dst_extents in 83 | // the new partition. 84 | // 85 | // The operations allowed in the payload (supported by the client) depend on the 86 | // major and minor version. See InstallOperation.Type below for details. 87 | syntax = "proto2"; 88 | package chromeos_update_engine; 89 | option optimize_for = LITE_RUNTIME; 90 | // Data is packed into blocks on disk, always starting from the beginning 91 | // of the block. If a file's data is too large for one block, it overflows 92 | // into another block, which may or may not be the following block on the 93 | // physical partition. An ordered list of extents is another 94 | // representation of an ordered list of blocks. For example, a file stored 95 | // in blocks 9, 10, 11, 2, 18, 12 (in that order) would be stored in 96 | // extents { {9, 3}, {2, 1}, {18, 1}, {12, 1} } (in that order). 97 | // In general, files are stored sequentially on disk, so it's more efficient 98 | // to use extents to encode the block lists (this is effectively 99 | // run-length encoding). 100 | // A sentinel value (kuint64max) as the start block denotes a sparse-hole 101 | // in a file whose block-length is specified by num_blocks. 102 | message Extent { 103 | optional uint64 start_block = 1; 104 | optional uint64 num_blocks = 2; 105 | } 106 | // Signatures: Updates may be signed by the OS vendor. The client verifies 107 | // an update's signature by hashing the entire download. The section of the 108 | // download that contains the signature is at the end of the file, so when 109 | // signing a file, only the part up to the signature part is signed. 110 | // Then, the client looks inside the download's Signatures message for a 111 | // Signature message that it knows how to handle. Generally, a client will 112 | // only know how to handle one type of signature, but an update may contain 113 | // many signatures to support many different types of client. Then client 114 | // selects a Signature message and uses that, along with a known public key, 115 | // to verify the download. The public key is expected to be part of the 116 | // client. 117 | message Signatures { 118 | message Signature { 119 | optional uint32 version = 1 [deprecated = true]; 120 | optional bytes data = 2; 121 | // The DER encoded signature size of EC keys is nondeterministic for 122 | // different input of sha256 hash. However, we need the size of the 123 | // serialized signatures protobuf string to be fixed before signing; 124 | // because this size is part of the content to be signed. Therefore, we 125 | // always pad the signature data to the maximum possible signature size of 126 | // a given key. And the payload verifier will truncate the signature to 127 | // its correct size based on the value of |unpadded_signature_size|. 128 | optional fixed32 unpadded_signature_size = 3; 129 | } 130 | repeated Signature signatures = 1; 131 | } 132 | message PartitionInfo { 133 | optional uint64 size = 1; 134 | optional bytes hash = 2; 135 | } 136 | // Describe an image we are based on in a human friendly way. 137 | // Examples: 138 | // dev-channel, x86-alex, 1.2.3, mp-v3 139 | // nplusone-channel, x86-alex, 1.2.4, mp-v3, dev-channel, 1.2.3 140 | // 141 | // All fields will be set, if this message is present. 142 | message ImageInfo { 143 | optional string board = 1; 144 | optional string key = 2; 145 | optional string channel = 3; 146 | optional string version = 4; 147 | // If these values aren't present, they should be assumed to match 148 | // the equivalent value above. They are normally only different for 149 | // special image types such as nplusone images. 150 | optional string build_channel = 5; 151 | optional string build_version = 6; 152 | } 153 | message InstallOperation { 154 | enum Type { 155 | REPLACE = 0; // Replace destination extents w/ attached data 156 | REPLACE_BZ = 1; // Replace destination extents w/ attached bzipped data 157 | MOVE = 2 [deprecated = true]; // Move source extents to destination extents 158 | BSDIFF = 3 [deprecated = true]; // The data is a bsdiff binary diff 159 | // On minor version 2 or newer, these operations are supported: 160 | SOURCE_COPY = 4; // Copy from source to target partition 161 | SOURCE_BSDIFF = 5; // Like BSDIFF, but read from source partition 162 | // On minor version 3 or newer and on major version 2 or newer, these 163 | // operations are supported: 164 | REPLACE_XZ = 8; // Replace destination extents w/ attached xz data. 165 | // On minor version 4 or newer, these operations are supported: 166 | ZERO = 6; // Write zeros in the destination. 167 | DISCARD = 7; // Discard the destination blocks, reading as undefined. 168 | BROTLI_BSDIFF = 10; // Like SOURCE_BSDIFF, but compressed with brotli. 169 | // On minor version 5 or newer, these operations are supported: 170 | PUFFDIFF = 9; // The data is in puffdiff format. 171 | } 172 | required Type type = 1; 173 | // Only minor version 6 or newer support 64 bits |data_offset| and 174 | // |data_length|, older client will read them as uint32. 175 | // The offset into the delta file (after the protobuf) 176 | // where the data (if any) is stored 177 | optional uint64 data_offset = 2; 178 | // The length of the data in the delta file 179 | optional uint64 data_length = 3; 180 | // Ordered list of extents that are read from (if any) and written to. 181 | repeated Extent src_extents = 4; 182 | // Byte length of src, equal to the number of blocks in src_extents * 183 | // block_size. It is used for BSDIFF and SOURCE_BSDIFF, because we need to 184 | // pass that external program the number of bytes to read from the blocks we 185 | // pass it. This is not used in any other operation. 186 | optional uint64 src_length = 5; 187 | repeated Extent dst_extents = 6; 188 | // Byte length of dst, equal to the number of blocks in dst_extents * 189 | // block_size. Used for BSDIFF and SOURCE_BSDIFF, but not in any other 190 | // operation. 191 | optional uint64 dst_length = 7; 192 | // Optional SHA 256 hash of the blob associated with this operation. 193 | // This is used as a primary validation for http-based downloads and 194 | // as a defense-in-depth validation for https-based downloads. If 195 | // the operation doesn't refer to any blob, this field will have 196 | // zero bytes. 197 | optional bytes data_sha256_hash = 8; 198 | // Indicates the SHA 256 hash of the source data referenced in src_extents at 199 | // the time of applying the operation. If present, the update_engine daemon 200 | // MUST read and verify the source data before applying the operation. 201 | optional bytes src_sha256_hash = 9; 202 | } 203 | // Describes the update to apply to a single partition. 204 | message PartitionUpdate { 205 | // A platform-specific name to identify the partition set being updated. For 206 | // example, in Chrome OS this could be "ROOT" or "KERNEL". 207 | required string partition_name = 1; 208 | // Whether this partition carries a filesystem with post-install program that 209 | // must be run to finalize the update process. See also |postinstall_path| and 210 | // |filesystem_type|. 211 | optional bool run_postinstall = 2; 212 | // The path of the executable program to run during the post-install step, 213 | // relative to the root of this filesystem. If not set, the default "postinst" 214 | // will be used. This setting is only used when |run_postinstall| is set and 215 | // true. 216 | optional string postinstall_path = 3; 217 | // The filesystem type as passed to the mount(2) syscall when mounting the new 218 | // filesystem to run the post-install program. If not set, a fixed list of 219 | // filesystems will be attempted. This setting is only used if 220 | // |run_postinstall| is set and true. 221 | optional string filesystem_type = 4; 222 | // If present, a list of signatures of the new_partition_info.hash signed with 223 | // different keys. If the update_engine daemon requires vendor-signed images 224 | // and has its public key installed, one of the signatures should be valid 225 | // for /postinstall to run. 226 | repeated Signatures.Signature new_partition_signature = 5; 227 | optional PartitionInfo old_partition_info = 6; 228 | optional PartitionInfo new_partition_info = 7; 229 | // The list of operations to be performed to apply this PartitionUpdate. The 230 | // associated operation blobs (in operations[i].data_offset, data_length) 231 | // should be stored contiguously and in the same order. 232 | repeated InstallOperation operations = 8; 233 | // Whether a failure in the postinstall step for this partition should be 234 | // ignored. 235 | optional bool postinstall_optional = 9; 236 | // On minor version 6 or newer, these fields are supported: 237 | // The extent for data covered by verity hash tree. 238 | optional Extent hash_tree_data_extent = 10; 239 | // The extent to store verity hash tree. 240 | optional Extent hash_tree_extent = 11; 241 | // The hash algorithm used in verity hash tree. 242 | optional string hash_tree_algorithm = 12; 243 | // The salt used for verity hash tree. 244 | optional bytes hash_tree_salt = 13; 245 | // The extent for data covered by FEC. 246 | optional Extent fec_data_extent = 14; 247 | // The extent to store FEC. 248 | optional Extent fec_extent = 15; 249 | // The number of FEC roots. 250 | optional uint32 fec_roots = 16 [default = 2]; 251 | } 252 | message DynamicPartitionGroup { 253 | // Name of the group. 254 | required string name = 1; 255 | // Maximum size of the group. The sum of sizes of all partitions in the group 256 | // must not exceed the maximum size of the group. 257 | optional uint64 size = 2; 258 | // A list of partitions that belong to the group. 259 | repeated string partition_names = 3; 260 | } 261 | // Metadata related to all dynamic partitions. 262 | message DynamicPartitionMetadata { 263 | // All updatable groups present in |partitions| of this DeltaArchiveManifest. 264 | // - If an updatable group is on the device but not in the manifest, it is 265 | // not updated. Hence, the group will not be resized, and partitions cannot 266 | // be added to or removed from the group. 267 | // - If an updatable group is in the manifest but not on the device, the group 268 | // is added to the device. 269 | repeated DynamicPartitionGroup groups = 1; 270 | // Whether dynamic partitions have snapshots during the update. If this is 271 | // set to true, the update_engine daemon creates snapshots for all dynamic 272 | // partitions if possible. If this is unset, the update_engine daemon MUST 273 | // NOT create snapshots for dynamic partitions. 274 | optional bool snapshot_enabled = 2; 275 | } 276 | message DeltaArchiveManifest { 277 | // Only present in major version = 1. List of install operations for the 278 | // kernel and rootfs partitions. For major version = 2 see the |partitions| 279 | // field. 280 | repeated InstallOperation install_operations = 1; 281 | repeated InstallOperation kernel_install_operations = 2; 282 | // (At time of writing) usually 4096 283 | optional uint32 block_size = 3 [default = 4096]; 284 | // If signatures are present, the offset into the blobs, generally 285 | // tacked onto the end of the file, and the length. We use an offset 286 | // rather than a bool to allow for more flexibility in future file formats. 287 | // If either is absent, it means signatures aren't supported in this 288 | // file. 289 | optional uint64 signatures_offset = 4; 290 | optional uint64 signatures_size = 5; 291 | // Only present in major version = 1. Partition metadata used to validate the 292 | // update. For major version = 2 see the |partitions| field. 293 | optional PartitionInfo old_kernel_info = 6; 294 | optional PartitionInfo new_kernel_info = 7; 295 | optional PartitionInfo old_rootfs_info = 8; 296 | optional PartitionInfo new_rootfs_info = 9; 297 | // old_image_info will only be present for delta images. 298 | optional ImageInfo old_image_info = 10; 299 | optional ImageInfo new_image_info = 11; 300 | // The minor version, also referred as "delta version", of the payload. 301 | // Minor version 0 is full payload, everything else is delta payload. 302 | optional uint32 minor_version = 12 [default = 0]; 303 | // Only present in major version >= 2. List of partitions that will be 304 | // updated, in the order they will be updated. This field replaces the 305 | // |install_operations|, |kernel_install_operations| and the 306 | // |{old,new}_{kernel,rootfs}_info| fields used in major version = 1. This 307 | // array can have more than two partitions if needed, and they are identified 308 | // by the partition name. 309 | repeated PartitionUpdate partitions = 13; 310 | // The maximum timestamp of the OS allowed to apply this payload. 311 | // Can be used to prevent downgrading the OS. 312 | optional int64 max_timestamp = 14; 313 | // Metadata related to all dynamic partitions. 314 | optional DynamicPartitionMetadata dynamic_partition_metadata = 15; 315 | } -------------------------------------------------------------------------------- /update_metadata.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // source: update_metadata.proto 3 | 4 | package main 5 | 6 | import ( 7 | fmt "fmt" 8 | proto "github.com/golang/protobuf/proto" 9 | math "math" 10 | ) 11 | 12 | // Reference imports to suppress errors if they are not otherwise used. 13 | var _ = proto.Marshal 14 | var _ = fmt.Errorf 15 | var _ = math.Inf 16 | 17 | // This is a compile-time assertion to ensure that this generated file 18 | // is compatible with the proto package it is being compiled against. 19 | // A compilation error at this line likely means your copy of the 20 | // proto package needs to be updated. 21 | const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package 22 | 23 | type InstallOperation_Type int32 24 | 25 | const ( 26 | InstallOperation_REPLACE InstallOperation_Type = 0 27 | InstallOperation_REPLACE_BZ InstallOperation_Type = 1 28 | InstallOperation_MOVE InstallOperation_Type = 2 // Deprecated: Do not use. 29 | InstallOperation_BSDIFF InstallOperation_Type = 3 // Deprecated: Do not use. 30 | // On minor version 2 or newer, these operations are supported: 31 | InstallOperation_SOURCE_COPY InstallOperation_Type = 4 32 | InstallOperation_SOURCE_BSDIFF InstallOperation_Type = 5 33 | // On minor version 3 or newer and on major version 2 or newer, these 34 | // operations are supported: 35 | InstallOperation_REPLACE_XZ InstallOperation_Type = 8 36 | // On minor version 4 or newer, these operations are supported: 37 | InstallOperation_ZERO InstallOperation_Type = 6 38 | InstallOperation_DISCARD InstallOperation_Type = 7 39 | InstallOperation_BROTLI_BSDIFF InstallOperation_Type = 10 40 | // On minor version 5 or newer, these operations are supported: 41 | InstallOperation_PUFFDIFF InstallOperation_Type = 9 42 | ) 43 | 44 | var InstallOperation_Type_name = map[int32]string{ 45 | 0: "REPLACE", 46 | 1: "REPLACE_BZ", 47 | 2: "MOVE", 48 | 3: "BSDIFF", 49 | 4: "SOURCE_COPY", 50 | 5: "SOURCE_BSDIFF", 51 | 8: "REPLACE_XZ", 52 | 6: "ZERO", 53 | 7: "DISCARD", 54 | 10: "BROTLI_BSDIFF", 55 | 9: "PUFFDIFF", 56 | } 57 | 58 | var InstallOperation_Type_value = map[string]int32{ 59 | "REPLACE": 0, 60 | "REPLACE_BZ": 1, 61 | "MOVE": 2, 62 | "BSDIFF": 3, 63 | "SOURCE_COPY": 4, 64 | "SOURCE_BSDIFF": 5, 65 | "REPLACE_XZ": 8, 66 | "ZERO": 6, 67 | "DISCARD": 7, 68 | "BROTLI_BSDIFF": 10, 69 | "PUFFDIFF": 9, 70 | } 71 | 72 | func (x InstallOperation_Type) Enum() *InstallOperation_Type { 73 | p := new(InstallOperation_Type) 74 | *p = x 75 | return p 76 | } 77 | 78 | func (x InstallOperation_Type) String() string { 79 | return proto.EnumName(InstallOperation_Type_name, int32(x)) 80 | } 81 | 82 | func (x *InstallOperation_Type) UnmarshalJSON(data []byte) error { 83 | value, err := proto.UnmarshalJSONEnum(InstallOperation_Type_value, data, "InstallOperation_Type") 84 | if err != nil { 85 | return err 86 | } 87 | *x = InstallOperation_Type(value) 88 | return nil 89 | } 90 | 91 | func (InstallOperation_Type) EnumDescriptor() ([]byte, []int) { 92 | return fileDescriptor_fa6d72a1ce634b79, []int{4, 0} 93 | } 94 | 95 | // Data is packed into blocks on disk, always starting from the beginning 96 | // of the block. If a file's data is too large for one block, it overflows 97 | // into another block, which may or may not be the following block on the 98 | // physical partition. An ordered list of extents is another 99 | // representation of an ordered list of blocks. For example, a file stored 100 | // in blocks 9, 10, 11, 2, 18, 12 (in that order) would be stored in 101 | // extents { {9, 3}, {2, 1}, {18, 1}, {12, 1} } (in that order). 102 | // In general, files are stored sequentially on disk, so it's more efficient 103 | // to use extents to encode the block lists (this is effectively 104 | // run-length encoding). 105 | // A sentinel value (kuint64max) as the start block denotes a sparse-hole 106 | // in a file whose block-length is specified by num_blocks. 107 | type Extent struct { 108 | StartBlock *uint64 `protobuf:"varint,1,opt,name=start_block,json=startBlock" json:"start_block,omitempty"` 109 | NumBlocks *uint64 `protobuf:"varint,2,opt,name=num_blocks,json=numBlocks" json:"num_blocks,omitempty"` 110 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 111 | XXX_unrecognized []byte `json:"-"` 112 | XXX_sizecache int32 `json:"-"` 113 | } 114 | 115 | func (m *Extent) Reset() { *m = Extent{} } 116 | func (m *Extent) String() string { return proto.CompactTextString(m) } 117 | func (*Extent) ProtoMessage() {} 118 | func (*Extent) Descriptor() ([]byte, []int) { 119 | return fileDescriptor_fa6d72a1ce634b79, []int{0} 120 | } 121 | 122 | func (m *Extent) XXX_Unmarshal(b []byte) error { 123 | return xxx_messageInfo_Extent.Unmarshal(m, b) 124 | } 125 | func (m *Extent) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 126 | return xxx_messageInfo_Extent.Marshal(b, m, deterministic) 127 | } 128 | func (m *Extent) XXX_Merge(src proto.Message) { 129 | xxx_messageInfo_Extent.Merge(m, src) 130 | } 131 | func (m *Extent) XXX_Size() int { 132 | return xxx_messageInfo_Extent.Size(m) 133 | } 134 | func (m *Extent) XXX_DiscardUnknown() { 135 | xxx_messageInfo_Extent.DiscardUnknown(m) 136 | } 137 | 138 | var xxx_messageInfo_Extent proto.InternalMessageInfo 139 | 140 | func (m *Extent) GetStartBlock() uint64 { 141 | if m != nil && m.StartBlock != nil { 142 | return *m.StartBlock 143 | } 144 | return 0 145 | } 146 | 147 | func (m *Extent) GetNumBlocks() uint64 { 148 | if m != nil && m.NumBlocks != nil { 149 | return *m.NumBlocks 150 | } 151 | return 0 152 | } 153 | 154 | // Signatures: Updates may be signed by the OS vendor. The client verifies 155 | // an update's signature by hashing the entire download. The section of the 156 | // download that contains the signature is at the end of the file, so when 157 | // signing a file, only the part up to the signature part is signed. 158 | // Then, the client looks inside the download's Signatures message for a 159 | // Signature message that it knows how to handle. Generally, a client will 160 | // only know how to handle one type of signature, but an update may contain 161 | // many signatures to support many different types of client. Then client 162 | // selects a Signature message and uses that, along with a known public key, 163 | // to verify the download. The public key is expected to be part of the 164 | // client. 165 | type Signatures struct { 166 | Signatures []*Signatures_Signature `protobuf:"bytes,1,rep,name=signatures" json:"signatures,omitempty"` 167 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 168 | XXX_unrecognized []byte `json:"-"` 169 | XXX_sizecache int32 `json:"-"` 170 | } 171 | 172 | func (m *Signatures) Reset() { *m = Signatures{} } 173 | func (m *Signatures) String() string { return proto.CompactTextString(m) } 174 | func (*Signatures) ProtoMessage() {} 175 | func (*Signatures) Descriptor() ([]byte, []int) { 176 | return fileDescriptor_fa6d72a1ce634b79, []int{1} 177 | } 178 | 179 | func (m *Signatures) XXX_Unmarshal(b []byte) error { 180 | return xxx_messageInfo_Signatures.Unmarshal(m, b) 181 | } 182 | func (m *Signatures) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 183 | return xxx_messageInfo_Signatures.Marshal(b, m, deterministic) 184 | } 185 | func (m *Signatures) XXX_Merge(src proto.Message) { 186 | xxx_messageInfo_Signatures.Merge(m, src) 187 | } 188 | func (m *Signatures) XXX_Size() int { 189 | return xxx_messageInfo_Signatures.Size(m) 190 | } 191 | func (m *Signatures) XXX_DiscardUnknown() { 192 | xxx_messageInfo_Signatures.DiscardUnknown(m) 193 | } 194 | 195 | var xxx_messageInfo_Signatures proto.InternalMessageInfo 196 | 197 | func (m *Signatures) GetSignatures() []*Signatures_Signature { 198 | if m != nil { 199 | return m.Signatures 200 | } 201 | return nil 202 | } 203 | 204 | type Signatures_Signature struct { 205 | Version *uint32 `protobuf:"varint,1,opt,name=version" json:"version,omitempty"` // Deprecated: Do not use. 206 | Data []byte `protobuf:"bytes,2,opt,name=data" json:"data,omitempty"` 207 | // The DER encoded signature size of EC keys is nondeterministic for 208 | // different input of sha256 hash. However, we need the size of the 209 | // serialized signatures protobuf string to be fixed before signing; 210 | // because this size is part of the content to be signed. Therefore, we 211 | // always pad the signature data to the maximum possible signature size of 212 | // a given key. And the payload verifier will truncate the signature to 213 | // its correct size based on the value of |unpadded_signature_size|. 214 | UnpaddedSignatureSize *uint32 `protobuf:"fixed32,3,opt,name=unpadded_signature_size,json=unpaddedSignatureSize" json:"unpadded_signature_size,omitempty"` 215 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 216 | XXX_unrecognized []byte `json:"-"` 217 | XXX_sizecache int32 `json:"-"` 218 | } 219 | 220 | func (m *Signatures_Signature) Reset() { *m = Signatures_Signature{} } 221 | func (m *Signatures_Signature) String() string { return proto.CompactTextString(m) } 222 | func (*Signatures_Signature) ProtoMessage() {} 223 | func (*Signatures_Signature) Descriptor() ([]byte, []int) { 224 | return fileDescriptor_fa6d72a1ce634b79, []int{1, 0} 225 | } 226 | 227 | func (m *Signatures_Signature) XXX_Unmarshal(b []byte) error { 228 | return xxx_messageInfo_Signatures_Signature.Unmarshal(m, b) 229 | } 230 | func (m *Signatures_Signature) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 231 | return xxx_messageInfo_Signatures_Signature.Marshal(b, m, deterministic) 232 | } 233 | func (m *Signatures_Signature) XXX_Merge(src proto.Message) { 234 | xxx_messageInfo_Signatures_Signature.Merge(m, src) 235 | } 236 | func (m *Signatures_Signature) XXX_Size() int { 237 | return xxx_messageInfo_Signatures_Signature.Size(m) 238 | } 239 | func (m *Signatures_Signature) XXX_DiscardUnknown() { 240 | xxx_messageInfo_Signatures_Signature.DiscardUnknown(m) 241 | } 242 | 243 | var xxx_messageInfo_Signatures_Signature proto.InternalMessageInfo 244 | 245 | // Deprecated: Do not use. 246 | func (m *Signatures_Signature) GetVersion() uint32 { 247 | if m != nil && m.Version != nil { 248 | return *m.Version 249 | } 250 | return 0 251 | } 252 | 253 | func (m *Signatures_Signature) GetData() []byte { 254 | if m != nil { 255 | return m.Data 256 | } 257 | return nil 258 | } 259 | 260 | func (m *Signatures_Signature) GetUnpaddedSignatureSize() uint32 { 261 | if m != nil && m.UnpaddedSignatureSize != nil { 262 | return *m.UnpaddedSignatureSize 263 | } 264 | return 0 265 | } 266 | 267 | type PartitionInfo struct { 268 | Size *uint64 `protobuf:"varint,1,opt,name=size" json:"size,omitempty"` 269 | Hash []byte `protobuf:"bytes,2,opt,name=hash" json:"hash,omitempty"` 270 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 271 | XXX_unrecognized []byte `json:"-"` 272 | XXX_sizecache int32 `json:"-"` 273 | } 274 | 275 | func (m *PartitionInfo) Reset() { *m = PartitionInfo{} } 276 | func (m *PartitionInfo) String() string { return proto.CompactTextString(m) } 277 | func (*PartitionInfo) ProtoMessage() {} 278 | func (*PartitionInfo) Descriptor() ([]byte, []int) { 279 | return fileDescriptor_fa6d72a1ce634b79, []int{2} 280 | } 281 | 282 | func (m *PartitionInfo) XXX_Unmarshal(b []byte) error { 283 | return xxx_messageInfo_PartitionInfo.Unmarshal(m, b) 284 | } 285 | func (m *PartitionInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 286 | return xxx_messageInfo_PartitionInfo.Marshal(b, m, deterministic) 287 | } 288 | func (m *PartitionInfo) XXX_Merge(src proto.Message) { 289 | xxx_messageInfo_PartitionInfo.Merge(m, src) 290 | } 291 | func (m *PartitionInfo) XXX_Size() int { 292 | return xxx_messageInfo_PartitionInfo.Size(m) 293 | } 294 | func (m *PartitionInfo) XXX_DiscardUnknown() { 295 | xxx_messageInfo_PartitionInfo.DiscardUnknown(m) 296 | } 297 | 298 | var xxx_messageInfo_PartitionInfo proto.InternalMessageInfo 299 | 300 | func (m *PartitionInfo) GetSize() uint64 { 301 | if m != nil && m.Size != nil { 302 | return *m.Size 303 | } 304 | return 0 305 | } 306 | 307 | func (m *PartitionInfo) GetHash() []byte { 308 | if m != nil { 309 | return m.Hash 310 | } 311 | return nil 312 | } 313 | 314 | // Describe an image we are based on in a human friendly way. 315 | // Examples: 316 | // dev-channel, x86-alex, 1.2.3, mp-v3 317 | // nplusone-channel, x86-alex, 1.2.4, mp-v3, dev-channel, 1.2.3 318 | // 319 | // All fields will be set, if this message is present. 320 | type ImageInfo struct { 321 | Board *string `protobuf:"bytes,1,opt,name=board" json:"board,omitempty"` 322 | Key *string `protobuf:"bytes,2,opt,name=key" json:"key,omitempty"` 323 | Channel *string `protobuf:"bytes,3,opt,name=channel" json:"channel,omitempty"` 324 | Version *string `protobuf:"bytes,4,opt,name=version" json:"version,omitempty"` 325 | // If these values aren't present, they should be assumed to match 326 | // the equivalent value above. They are normally only different for 327 | // special image types such as nplusone images. 328 | BuildChannel *string `protobuf:"bytes,5,opt,name=build_channel,json=buildChannel" json:"build_channel,omitempty"` 329 | BuildVersion *string `protobuf:"bytes,6,opt,name=build_version,json=buildVersion" json:"build_version,omitempty"` 330 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 331 | XXX_unrecognized []byte `json:"-"` 332 | XXX_sizecache int32 `json:"-"` 333 | } 334 | 335 | func (m *ImageInfo) Reset() { *m = ImageInfo{} } 336 | func (m *ImageInfo) String() string { return proto.CompactTextString(m) } 337 | func (*ImageInfo) ProtoMessage() {} 338 | func (*ImageInfo) Descriptor() ([]byte, []int) { 339 | return fileDescriptor_fa6d72a1ce634b79, []int{3} 340 | } 341 | 342 | func (m *ImageInfo) XXX_Unmarshal(b []byte) error { 343 | return xxx_messageInfo_ImageInfo.Unmarshal(m, b) 344 | } 345 | func (m *ImageInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 346 | return xxx_messageInfo_ImageInfo.Marshal(b, m, deterministic) 347 | } 348 | func (m *ImageInfo) XXX_Merge(src proto.Message) { 349 | xxx_messageInfo_ImageInfo.Merge(m, src) 350 | } 351 | func (m *ImageInfo) XXX_Size() int { 352 | return xxx_messageInfo_ImageInfo.Size(m) 353 | } 354 | func (m *ImageInfo) XXX_DiscardUnknown() { 355 | xxx_messageInfo_ImageInfo.DiscardUnknown(m) 356 | } 357 | 358 | var xxx_messageInfo_ImageInfo proto.InternalMessageInfo 359 | 360 | func (m *ImageInfo) GetBoard() string { 361 | if m != nil && m.Board != nil { 362 | return *m.Board 363 | } 364 | return "" 365 | } 366 | 367 | func (m *ImageInfo) GetKey() string { 368 | if m != nil && m.Key != nil { 369 | return *m.Key 370 | } 371 | return "" 372 | } 373 | 374 | func (m *ImageInfo) GetChannel() string { 375 | if m != nil && m.Channel != nil { 376 | return *m.Channel 377 | } 378 | return "" 379 | } 380 | 381 | func (m *ImageInfo) GetVersion() string { 382 | if m != nil && m.Version != nil { 383 | return *m.Version 384 | } 385 | return "" 386 | } 387 | 388 | func (m *ImageInfo) GetBuildChannel() string { 389 | if m != nil && m.BuildChannel != nil { 390 | return *m.BuildChannel 391 | } 392 | return "" 393 | } 394 | 395 | func (m *ImageInfo) GetBuildVersion() string { 396 | if m != nil && m.BuildVersion != nil { 397 | return *m.BuildVersion 398 | } 399 | return "" 400 | } 401 | 402 | type InstallOperation struct { 403 | Type *InstallOperation_Type `protobuf:"varint,1,req,name=type,enum=chromeos_update_engine.InstallOperation_Type" json:"type,omitempty"` 404 | // Only minor version 6 or newer support 64 bits |data_offset| and 405 | // |data_length|, older client will read them as uint32. 406 | // The offset into the delta file (after the protobuf) 407 | // where the data (if any) is stored 408 | DataOffset *uint64 `protobuf:"varint,2,opt,name=data_offset,json=dataOffset" json:"data_offset,omitempty"` 409 | // The length of the data in the delta file 410 | DataLength *uint64 `protobuf:"varint,3,opt,name=data_length,json=dataLength" json:"data_length,omitempty"` 411 | // Ordered list of extents that are read from (if any) and written to. 412 | SrcExtents []*Extent `protobuf:"bytes,4,rep,name=src_extents,json=srcExtents" json:"src_extents,omitempty"` 413 | // Byte length of src, equal to the number of blocks in src_extents * 414 | // block_size. It is used for BSDIFF and SOURCE_BSDIFF, because we need to 415 | // pass that external program the number of bytes to read from the blocks we 416 | // pass it. This is not used in any other operation. 417 | SrcLength *uint64 `protobuf:"varint,5,opt,name=src_length,json=srcLength" json:"src_length,omitempty"` 418 | DstExtents []*Extent `protobuf:"bytes,6,rep,name=dst_extents,json=dstExtents" json:"dst_extents,omitempty"` 419 | // Byte length of dst, equal to the number of blocks in dst_extents * 420 | // block_size. Used for BSDIFF and SOURCE_BSDIFF, but not in any other 421 | // operation. 422 | DstLength *uint64 `protobuf:"varint,7,opt,name=dst_length,json=dstLength" json:"dst_length,omitempty"` 423 | // Optional SHA 256 hash of the blob associated with this operation. 424 | // This is used as a primary validation for http-based downloads and 425 | // as a defense-in-depth validation for https-based downloads. If 426 | // the operation doesn't refer to any blob, this field will have 427 | // zero bytes. 428 | DataSha256Hash []byte `protobuf:"bytes,8,opt,name=data_sha256_hash,json=dataSha256Hash" json:"data_sha256_hash,omitempty"` 429 | // Indicates the SHA 256 hash of the source data referenced in src_extents at 430 | // the time of applying the operation. If present, the update_engine daemon 431 | // MUST read and verify the source data before applying the operation. 432 | SrcSha256Hash []byte `protobuf:"bytes,9,opt,name=src_sha256_hash,json=srcSha256Hash" json:"src_sha256_hash,omitempty"` 433 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 434 | XXX_unrecognized []byte `json:"-"` 435 | XXX_sizecache int32 `json:"-"` 436 | } 437 | 438 | func (m *InstallOperation) Reset() { *m = InstallOperation{} } 439 | func (m *InstallOperation) String() string { return proto.CompactTextString(m) } 440 | func (*InstallOperation) ProtoMessage() {} 441 | func (*InstallOperation) Descriptor() ([]byte, []int) { 442 | return fileDescriptor_fa6d72a1ce634b79, []int{4} 443 | } 444 | 445 | func (m *InstallOperation) XXX_Unmarshal(b []byte) error { 446 | return xxx_messageInfo_InstallOperation.Unmarshal(m, b) 447 | } 448 | func (m *InstallOperation) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 449 | return xxx_messageInfo_InstallOperation.Marshal(b, m, deterministic) 450 | } 451 | func (m *InstallOperation) XXX_Merge(src proto.Message) { 452 | xxx_messageInfo_InstallOperation.Merge(m, src) 453 | } 454 | func (m *InstallOperation) XXX_Size() int { 455 | return xxx_messageInfo_InstallOperation.Size(m) 456 | } 457 | func (m *InstallOperation) XXX_DiscardUnknown() { 458 | xxx_messageInfo_InstallOperation.DiscardUnknown(m) 459 | } 460 | 461 | var xxx_messageInfo_InstallOperation proto.InternalMessageInfo 462 | 463 | func (m *InstallOperation) GetType() InstallOperation_Type { 464 | if m != nil && m.Type != nil { 465 | return *m.Type 466 | } 467 | return InstallOperation_REPLACE 468 | } 469 | 470 | func (m *InstallOperation) GetDataOffset() uint64 { 471 | if m != nil && m.DataOffset != nil { 472 | return *m.DataOffset 473 | } 474 | return 0 475 | } 476 | 477 | func (m *InstallOperation) GetDataLength() uint64 { 478 | if m != nil && m.DataLength != nil { 479 | return *m.DataLength 480 | } 481 | return 0 482 | } 483 | 484 | func (m *InstallOperation) GetSrcExtents() []*Extent { 485 | if m != nil { 486 | return m.SrcExtents 487 | } 488 | return nil 489 | } 490 | 491 | func (m *InstallOperation) GetSrcLength() uint64 { 492 | if m != nil && m.SrcLength != nil { 493 | return *m.SrcLength 494 | } 495 | return 0 496 | } 497 | 498 | func (m *InstallOperation) GetDstExtents() []*Extent { 499 | if m != nil { 500 | return m.DstExtents 501 | } 502 | return nil 503 | } 504 | 505 | func (m *InstallOperation) GetDstLength() uint64 { 506 | if m != nil && m.DstLength != nil { 507 | return *m.DstLength 508 | } 509 | return 0 510 | } 511 | 512 | func (m *InstallOperation) GetDataSha256Hash() []byte { 513 | if m != nil { 514 | return m.DataSha256Hash 515 | } 516 | return nil 517 | } 518 | 519 | func (m *InstallOperation) GetSrcSha256Hash() []byte { 520 | if m != nil { 521 | return m.SrcSha256Hash 522 | } 523 | return nil 524 | } 525 | 526 | // Describes the update to apply to a single partition. 527 | type PartitionUpdate struct { 528 | // A platform-specific name to identify the partition set being updated. For 529 | // example, in Chrome OS this could be "ROOT" or "KERNEL". 530 | PartitionName *string `protobuf:"bytes,1,req,name=partition_name,json=partitionName" json:"partition_name,omitempty"` 531 | // Whether this partition carries a filesystem with post-install program that 532 | // must be run to finalize the update process. See also |postinstall_path| and 533 | // |filesystem_type|. 534 | RunPostinstall *bool `protobuf:"varint,2,opt,name=run_postinstall,json=runPostinstall" json:"run_postinstall,omitempty"` 535 | // The path of the executable program to run during the post-install step, 536 | // relative to the root of this filesystem. If not set, the default "postinst" 537 | // will be used. This setting is only used when |run_postinstall| is set and 538 | // true. 539 | PostinstallPath *string `protobuf:"bytes,3,opt,name=postinstall_path,json=postinstallPath" json:"postinstall_path,omitempty"` 540 | // The filesystem type as passed to the mount(2) syscall when mounting the new 541 | // filesystem to run the post-install program. If not set, a fixed list of 542 | // filesystems will be attempted. This setting is only used if 543 | // |run_postinstall| is set and true. 544 | FilesystemType *string `protobuf:"bytes,4,opt,name=filesystem_type,json=filesystemType" json:"filesystem_type,omitempty"` 545 | // If present, a list of signatures of the new_partition_info.hash signed with 546 | // different keys. If the update_engine daemon requires vendor-signed images 547 | // and has its public key installed, one of the signatures should be valid 548 | // for /postinstall to run. 549 | NewPartitionSignature []*Signatures_Signature `protobuf:"bytes,5,rep,name=new_partition_signature,json=newPartitionSignature" json:"new_partition_signature,omitempty"` 550 | OldPartitionInfo *PartitionInfo `protobuf:"bytes,6,opt,name=old_partition_info,json=oldPartitionInfo" json:"old_partition_info,omitempty"` 551 | NewPartitionInfo *PartitionInfo `protobuf:"bytes,7,opt,name=new_partition_info,json=newPartitionInfo" json:"new_partition_info,omitempty"` 552 | // The list of operations to be performed to apply this PartitionUpdate. The 553 | // associated operation blobs (in operations[i].data_offset, data_length) 554 | // should be stored contiguously and in the same order. 555 | Operations []*InstallOperation `protobuf:"bytes,8,rep,name=operations" json:"operations,omitempty"` 556 | // Whether a failure in the postinstall step for this partition should be 557 | // ignored. 558 | PostinstallOptional *bool `protobuf:"varint,9,opt,name=postinstall_optional,json=postinstallOptional" json:"postinstall_optional,omitempty"` 559 | // On minor version 6 or newer, these fields are supported: 560 | // The extent for data covered by verity hash tree. 561 | HashTreeDataExtent *Extent `protobuf:"bytes,10,opt,name=hash_tree_data_extent,json=hashTreeDataExtent" json:"hash_tree_data_extent,omitempty"` 562 | // The extent to store verity hash tree. 563 | HashTreeExtent *Extent `protobuf:"bytes,11,opt,name=hash_tree_extent,json=hashTreeExtent" json:"hash_tree_extent,omitempty"` 564 | // The hash algorithm used in verity hash tree. 565 | HashTreeAlgorithm *string `protobuf:"bytes,12,opt,name=hash_tree_algorithm,json=hashTreeAlgorithm" json:"hash_tree_algorithm,omitempty"` 566 | // The salt used for verity hash tree. 567 | HashTreeSalt []byte `protobuf:"bytes,13,opt,name=hash_tree_salt,json=hashTreeSalt" json:"hash_tree_salt,omitempty"` 568 | // The extent for data covered by FEC. 569 | FecDataExtent *Extent `protobuf:"bytes,14,opt,name=fec_data_extent,json=fecDataExtent" json:"fec_data_extent,omitempty"` 570 | // The extent to store FEC. 571 | FecExtent *Extent `protobuf:"bytes,15,opt,name=fec_extent,json=fecExtent" json:"fec_extent,omitempty"` 572 | // The number of FEC roots. 573 | FecRoots *uint32 `protobuf:"varint,16,opt,name=fec_roots,json=fecRoots,def=2" json:"fec_roots,omitempty"` 574 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 575 | XXX_unrecognized []byte `json:"-"` 576 | XXX_sizecache int32 `json:"-"` 577 | } 578 | 579 | func (m *PartitionUpdate) Reset() { *m = PartitionUpdate{} } 580 | func (m *PartitionUpdate) String() string { return proto.CompactTextString(m) } 581 | func (*PartitionUpdate) ProtoMessage() {} 582 | func (*PartitionUpdate) Descriptor() ([]byte, []int) { 583 | return fileDescriptor_fa6d72a1ce634b79, []int{5} 584 | } 585 | 586 | func (m *PartitionUpdate) XXX_Unmarshal(b []byte) error { 587 | return xxx_messageInfo_PartitionUpdate.Unmarshal(m, b) 588 | } 589 | func (m *PartitionUpdate) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 590 | return xxx_messageInfo_PartitionUpdate.Marshal(b, m, deterministic) 591 | } 592 | func (m *PartitionUpdate) XXX_Merge(src proto.Message) { 593 | xxx_messageInfo_PartitionUpdate.Merge(m, src) 594 | } 595 | func (m *PartitionUpdate) XXX_Size() int { 596 | return xxx_messageInfo_PartitionUpdate.Size(m) 597 | } 598 | func (m *PartitionUpdate) XXX_DiscardUnknown() { 599 | xxx_messageInfo_PartitionUpdate.DiscardUnknown(m) 600 | } 601 | 602 | var xxx_messageInfo_PartitionUpdate proto.InternalMessageInfo 603 | 604 | const Default_PartitionUpdate_FecRoots uint32 = 2 605 | 606 | func (m *PartitionUpdate) GetPartitionName() string { 607 | if m != nil && m.PartitionName != nil { 608 | return *m.PartitionName 609 | } 610 | return "" 611 | } 612 | 613 | func (m *PartitionUpdate) GetRunPostinstall() bool { 614 | if m != nil && m.RunPostinstall != nil { 615 | return *m.RunPostinstall 616 | } 617 | return false 618 | } 619 | 620 | func (m *PartitionUpdate) GetPostinstallPath() string { 621 | if m != nil && m.PostinstallPath != nil { 622 | return *m.PostinstallPath 623 | } 624 | return "" 625 | } 626 | 627 | func (m *PartitionUpdate) GetFilesystemType() string { 628 | if m != nil && m.FilesystemType != nil { 629 | return *m.FilesystemType 630 | } 631 | return "" 632 | } 633 | 634 | func (m *PartitionUpdate) GetNewPartitionSignature() []*Signatures_Signature { 635 | if m != nil { 636 | return m.NewPartitionSignature 637 | } 638 | return nil 639 | } 640 | 641 | func (m *PartitionUpdate) GetOldPartitionInfo() *PartitionInfo { 642 | if m != nil { 643 | return m.OldPartitionInfo 644 | } 645 | return nil 646 | } 647 | 648 | func (m *PartitionUpdate) GetNewPartitionInfo() *PartitionInfo { 649 | if m != nil { 650 | return m.NewPartitionInfo 651 | } 652 | return nil 653 | } 654 | 655 | func (m *PartitionUpdate) GetOperations() []*InstallOperation { 656 | if m != nil { 657 | return m.Operations 658 | } 659 | return nil 660 | } 661 | 662 | func (m *PartitionUpdate) GetPostinstallOptional() bool { 663 | if m != nil && m.PostinstallOptional != nil { 664 | return *m.PostinstallOptional 665 | } 666 | return false 667 | } 668 | 669 | func (m *PartitionUpdate) GetHashTreeDataExtent() *Extent { 670 | if m != nil { 671 | return m.HashTreeDataExtent 672 | } 673 | return nil 674 | } 675 | 676 | func (m *PartitionUpdate) GetHashTreeExtent() *Extent { 677 | if m != nil { 678 | return m.HashTreeExtent 679 | } 680 | return nil 681 | } 682 | 683 | func (m *PartitionUpdate) GetHashTreeAlgorithm() string { 684 | if m != nil && m.HashTreeAlgorithm != nil { 685 | return *m.HashTreeAlgorithm 686 | } 687 | return "" 688 | } 689 | 690 | func (m *PartitionUpdate) GetHashTreeSalt() []byte { 691 | if m != nil { 692 | return m.HashTreeSalt 693 | } 694 | return nil 695 | } 696 | 697 | func (m *PartitionUpdate) GetFecDataExtent() *Extent { 698 | if m != nil { 699 | return m.FecDataExtent 700 | } 701 | return nil 702 | } 703 | 704 | func (m *PartitionUpdate) GetFecExtent() *Extent { 705 | if m != nil { 706 | return m.FecExtent 707 | } 708 | return nil 709 | } 710 | 711 | func (m *PartitionUpdate) GetFecRoots() uint32 { 712 | if m != nil && m.FecRoots != nil { 713 | return *m.FecRoots 714 | } 715 | return Default_PartitionUpdate_FecRoots 716 | } 717 | 718 | type DynamicPartitionGroup struct { 719 | // Name of the group. 720 | Name *string `protobuf:"bytes,1,req,name=name" json:"name,omitempty"` 721 | // Maximum size of the group. The sum of sizes of all partitions in the group 722 | // must not exceed the maximum size of the group. 723 | Size *uint64 `protobuf:"varint,2,opt,name=size" json:"size,omitempty"` 724 | // A list of partitions that belong to the group. 725 | PartitionNames []string `protobuf:"bytes,3,rep,name=partition_names,json=partitionNames" json:"partition_names,omitempty"` 726 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 727 | XXX_unrecognized []byte `json:"-"` 728 | XXX_sizecache int32 `json:"-"` 729 | } 730 | 731 | func (m *DynamicPartitionGroup) Reset() { *m = DynamicPartitionGroup{} } 732 | func (m *DynamicPartitionGroup) String() string { return proto.CompactTextString(m) } 733 | func (*DynamicPartitionGroup) ProtoMessage() {} 734 | func (*DynamicPartitionGroup) Descriptor() ([]byte, []int) { 735 | return fileDescriptor_fa6d72a1ce634b79, []int{6} 736 | } 737 | 738 | func (m *DynamicPartitionGroup) XXX_Unmarshal(b []byte) error { 739 | return xxx_messageInfo_DynamicPartitionGroup.Unmarshal(m, b) 740 | } 741 | func (m *DynamicPartitionGroup) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 742 | return xxx_messageInfo_DynamicPartitionGroup.Marshal(b, m, deterministic) 743 | } 744 | func (m *DynamicPartitionGroup) XXX_Merge(src proto.Message) { 745 | xxx_messageInfo_DynamicPartitionGroup.Merge(m, src) 746 | } 747 | func (m *DynamicPartitionGroup) XXX_Size() int { 748 | return xxx_messageInfo_DynamicPartitionGroup.Size(m) 749 | } 750 | func (m *DynamicPartitionGroup) XXX_DiscardUnknown() { 751 | xxx_messageInfo_DynamicPartitionGroup.DiscardUnknown(m) 752 | } 753 | 754 | var xxx_messageInfo_DynamicPartitionGroup proto.InternalMessageInfo 755 | 756 | func (m *DynamicPartitionGroup) GetName() string { 757 | if m != nil && m.Name != nil { 758 | return *m.Name 759 | } 760 | return "" 761 | } 762 | 763 | func (m *DynamicPartitionGroup) GetSize() uint64 { 764 | if m != nil && m.Size != nil { 765 | return *m.Size 766 | } 767 | return 0 768 | } 769 | 770 | func (m *DynamicPartitionGroup) GetPartitionNames() []string { 771 | if m != nil { 772 | return m.PartitionNames 773 | } 774 | return nil 775 | } 776 | 777 | // Metadata related to all dynamic partitions. 778 | type DynamicPartitionMetadata struct { 779 | // All updatable groups present in |partitions| of this DeltaArchiveManifest. 780 | // - If an updatable group is on the device but not in the manifest, it is 781 | // not updated. Hence, the group will not be resized, and partitions cannot 782 | // be added to or removed from the group. 783 | // - If an updatable group is in the manifest but not on the device, the group 784 | // is added to the device. 785 | Groups []*DynamicPartitionGroup `protobuf:"bytes,1,rep,name=groups" json:"groups,omitempty"` 786 | // Whether dynamic partitions have snapshots during the update. If this is 787 | // set to true, the update_engine daemon creates snapshots for all dynamic 788 | // partitions if possible. If this is unset, the update_engine daemon MUST 789 | // NOT create snapshots for dynamic partitions. 790 | SnapshotEnabled *bool `protobuf:"varint,2,opt,name=snapshot_enabled,json=snapshotEnabled" json:"snapshot_enabled,omitempty"` 791 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 792 | XXX_unrecognized []byte `json:"-"` 793 | XXX_sizecache int32 `json:"-"` 794 | } 795 | 796 | func (m *DynamicPartitionMetadata) Reset() { *m = DynamicPartitionMetadata{} } 797 | func (m *DynamicPartitionMetadata) String() string { return proto.CompactTextString(m) } 798 | func (*DynamicPartitionMetadata) ProtoMessage() {} 799 | func (*DynamicPartitionMetadata) Descriptor() ([]byte, []int) { 800 | return fileDescriptor_fa6d72a1ce634b79, []int{7} 801 | } 802 | 803 | func (m *DynamicPartitionMetadata) XXX_Unmarshal(b []byte) error { 804 | return xxx_messageInfo_DynamicPartitionMetadata.Unmarshal(m, b) 805 | } 806 | func (m *DynamicPartitionMetadata) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 807 | return xxx_messageInfo_DynamicPartitionMetadata.Marshal(b, m, deterministic) 808 | } 809 | func (m *DynamicPartitionMetadata) XXX_Merge(src proto.Message) { 810 | xxx_messageInfo_DynamicPartitionMetadata.Merge(m, src) 811 | } 812 | func (m *DynamicPartitionMetadata) XXX_Size() int { 813 | return xxx_messageInfo_DynamicPartitionMetadata.Size(m) 814 | } 815 | func (m *DynamicPartitionMetadata) XXX_DiscardUnknown() { 816 | xxx_messageInfo_DynamicPartitionMetadata.DiscardUnknown(m) 817 | } 818 | 819 | var xxx_messageInfo_DynamicPartitionMetadata proto.InternalMessageInfo 820 | 821 | func (m *DynamicPartitionMetadata) GetGroups() []*DynamicPartitionGroup { 822 | if m != nil { 823 | return m.Groups 824 | } 825 | return nil 826 | } 827 | 828 | func (m *DynamicPartitionMetadata) GetSnapshotEnabled() bool { 829 | if m != nil && m.SnapshotEnabled != nil { 830 | return *m.SnapshotEnabled 831 | } 832 | return false 833 | } 834 | 835 | type DeltaArchiveManifest struct { 836 | // Only present in major version = 1. List of install operations for the 837 | // kernel and rootfs partitions. For major version = 2 see the |partitions| 838 | // field. 839 | InstallOperations []*InstallOperation `protobuf:"bytes,1,rep,name=install_operations,json=installOperations" json:"install_operations,omitempty"` 840 | KernelInstallOperations []*InstallOperation `protobuf:"bytes,2,rep,name=kernel_install_operations,json=kernelInstallOperations" json:"kernel_install_operations,omitempty"` 841 | // (At time of writing) usually 4096 842 | BlockSize *uint32 `protobuf:"varint,3,opt,name=block_size,json=blockSize,def=4096" json:"block_size,omitempty"` 843 | // If signatures are present, the offset into the blobs, generally 844 | // tacked onto the end of the file, and the length. We use an offset 845 | // rather than a bool to allow for more flexibility in future file formats. 846 | // If either is absent, it means signatures aren't supported in this 847 | // file. 848 | SignaturesOffset *uint64 `protobuf:"varint,4,opt,name=signatures_offset,json=signaturesOffset" json:"signatures_offset,omitempty"` 849 | SignaturesSize *uint64 `protobuf:"varint,5,opt,name=signatures_size,json=signaturesSize" json:"signatures_size,omitempty"` 850 | // Only present in major version = 1. Partition metadata used to validate the 851 | // update. For major version = 2 see the |partitions| field. 852 | OldKernelInfo *PartitionInfo `protobuf:"bytes,6,opt,name=old_kernel_info,json=oldKernelInfo" json:"old_kernel_info,omitempty"` 853 | NewKernelInfo *PartitionInfo `protobuf:"bytes,7,opt,name=new_kernel_info,json=newKernelInfo" json:"new_kernel_info,omitempty"` 854 | OldRootfsInfo *PartitionInfo `protobuf:"bytes,8,opt,name=old_rootfs_info,json=oldRootfsInfo" json:"old_rootfs_info,omitempty"` 855 | NewRootfsInfo *PartitionInfo `protobuf:"bytes,9,opt,name=new_rootfs_info,json=newRootfsInfo" json:"new_rootfs_info,omitempty"` 856 | // old_image_info will only be present for delta images. 857 | OldImageInfo *ImageInfo `protobuf:"bytes,10,opt,name=old_image_info,json=oldImageInfo" json:"old_image_info,omitempty"` 858 | NewImageInfo *ImageInfo `protobuf:"bytes,11,opt,name=new_image_info,json=newImageInfo" json:"new_image_info,omitempty"` 859 | // The minor version, also referred as "delta version", of the payload. 860 | // Minor version 0 is full payload, everything else is delta payload. 861 | MinorVersion *uint32 `protobuf:"varint,12,opt,name=minor_version,json=minorVersion,def=0" json:"minor_version,omitempty"` 862 | // Only present in major version >= 2. List of partitions that will be 863 | // updated, in the order they will be updated. This field replaces the 864 | // |install_operations|, |kernel_install_operations| and the 865 | // |{old,new}_{kernel,rootfs}_info| fields used in major version = 1. This 866 | // array can have more than two partitions if needed, and they are identified 867 | // by the partition name. 868 | Partitions []*PartitionUpdate `protobuf:"bytes,13,rep,name=partitions" json:"partitions,omitempty"` 869 | // The maximum timestamp of the OS allowed to apply this payload. 870 | // Can be used to prevent downgrading the OS. 871 | MaxTimestamp *int64 `protobuf:"varint,14,opt,name=max_timestamp,json=maxTimestamp" json:"max_timestamp,omitempty"` 872 | // Metadata related to all dynamic partitions. 873 | DynamicPartitionMetadata *DynamicPartitionMetadata `protobuf:"bytes,15,opt,name=dynamic_partition_metadata,json=dynamicPartitionMetadata" json:"dynamic_partition_metadata,omitempty"` 874 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 875 | XXX_unrecognized []byte `json:"-"` 876 | XXX_sizecache int32 `json:"-"` 877 | } 878 | 879 | func (m *DeltaArchiveManifest) Reset() { *m = DeltaArchiveManifest{} } 880 | func (m *DeltaArchiveManifest) String() string { return proto.CompactTextString(m) } 881 | func (*DeltaArchiveManifest) ProtoMessage() {} 882 | func (*DeltaArchiveManifest) Descriptor() ([]byte, []int) { 883 | return fileDescriptor_fa6d72a1ce634b79, []int{8} 884 | } 885 | 886 | func (m *DeltaArchiveManifest) XXX_Unmarshal(b []byte) error { 887 | return xxx_messageInfo_DeltaArchiveManifest.Unmarshal(m, b) 888 | } 889 | func (m *DeltaArchiveManifest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 890 | return xxx_messageInfo_DeltaArchiveManifest.Marshal(b, m, deterministic) 891 | } 892 | func (m *DeltaArchiveManifest) XXX_Merge(src proto.Message) { 893 | xxx_messageInfo_DeltaArchiveManifest.Merge(m, src) 894 | } 895 | func (m *DeltaArchiveManifest) XXX_Size() int { 896 | return xxx_messageInfo_DeltaArchiveManifest.Size(m) 897 | } 898 | func (m *DeltaArchiveManifest) XXX_DiscardUnknown() { 899 | xxx_messageInfo_DeltaArchiveManifest.DiscardUnknown(m) 900 | } 901 | 902 | var xxx_messageInfo_DeltaArchiveManifest proto.InternalMessageInfo 903 | 904 | const Default_DeltaArchiveManifest_BlockSize uint32 = 4096 905 | const Default_DeltaArchiveManifest_MinorVersion uint32 = 0 906 | 907 | func (m *DeltaArchiveManifest) GetInstallOperations() []*InstallOperation { 908 | if m != nil { 909 | return m.InstallOperations 910 | } 911 | return nil 912 | } 913 | 914 | func (m *DeltaArchiveManifest) GetKernelInstallOperations() []*InstallOperation { 915 | if m != nil { 916 | return m.KernelInstallOperations 917 | } 918 | return nil 919 | } 920 | 921 | func (m *DeltaArchiveManifest) GetBlockSize() uint32 { 922 | if m != nil && m.BlockSize != nil { 923 | return *m.BlockSize 924 | } 925 | return Default_DeltaArchiveManifest_BlockSize 926 | } 927 | 928 | func (m *DeltaArchiveManifest) GetSignaturesOffset() uint64 { 929 | if m != nil && m.SignaturesOffset != nil { 930 | return *m.SignaturesOffset 931 | } 932 | return 0 933 | } 934 | 935 | func (m *DeltaArchiveManifest) GetSignaturesSize() uint64 { 936 | if m != nil && m.SignaturesSize != nil { 937 | return *m.SignaturesSize 938 | } 939 | return 0 940 | } 941 | 942 | func (m *DeltaArchiveManifest) GetOldKernelInfo() *PartitionInfo { 943 | if m != nil { 944 | return m.OldKernelInfo 945 | } 946 | return nil 947 | } 948 | 949 | func (m *DeltaArchiveManifest) GetNewKernelInfo() *PartitionInfo { 950 | if m != nil { 951 | return m.NewKernelInfo 952 | } 953 | return nil 954 | } 955 | 956 | func (m *DeltaArchiveManifest) GetOldRootfsInfo() *PartitionInfo { 957 | if m != nil { 958 | return m.OldRootfsInfo 959 | } 960 | return nil 961 | } 962 | 963 | func (m *DeltaArchiveManifest) GetNewRootfsInfo() *PartitionInfo { 964 | if m != nil { 965 | return m.NewRootfsInfo 966 | } 967 | return nil 968 | } 969 | 970 | func (m *DeltaArchiveManifest) GetOldImageInfo() *ImageInfo { 971 | if m != nil { 972 | return m.OldImageInfo 973 | } 974 | return nil 975 | } 976 | 977 | func (m *DeltaArchiveManifest) GetNewImageInfo() *ImageInfo { 978 | if m != nil { 979 | return m.NewImageInfo 980 | } 981 | return nil 982 | } 983 | 984 | func (m *DeltaArchiveManifest) GetMinorVersion() uint32 { 985 | if m != nil && m.MinorVersion != nil { 986 | return *m.MinorVersion 987 | } 988 | return Default_DeltaArchiveManifest_MinorVersion 989 | } 990 | 991 | func (m *DeltaArchiveManifest) GetPartitions() []*PartitionUpdate { 992 | if m != nil { 993 | return m.Partitions 994 | } 995 | return nil 996 | } 997 | 998 | func (m *DeltaArchiveManifest) GetMaxTimestamp() int64 { 999 | if m != nil && m.MaxTimestamp != nil { 1000 | return *m.MaxTimestamp 1001 | } 1002 | return 0 1003 | } 1004 | 1005 | func (m *DeltaArchiveManifest) GetDynamicPartitionMetadata() *DynamicPartitionMetadata { 1006 | if m != nil { 1007 | return m.DynamicPartitionMetadata 1008 | } 1009 | return nil 1010 | } 1011 | 1012 | func init() { 1013 | proto.RegisterEnum("chromeos_update_engine.InstallOperation_Type", InstallOperation_Type_name, InstallOperation_Type_value) 1014 | proto.RegisterType((*Extent)(nil), "chromeos_update_engine.Extent") 1015 | proto.RegisterType((*Signatures)(nil), "chromeos_update_engine.Signatures") 1016 | proto.RegisterType((*Signatures_Signature)(nil), "chromeos_update_engine.Signatures.Signature") 1017 | proto.RegisterType((*PartitionInfo)(nil), "chromeos_update_engine.PartitionInfo") 1018 | proto.RegisterType((*ImageInfo)(nil), "chromeos_update_engine.ImageInfo") 1019 | proto.RegisterType((*InstallOperation)(nil), "chromeos_update_engine.InstallOperation") 1020 | proto.RegisterType((*PartitionUpdate)(nil), "chromeos_update_engine.PartitionUpdate") 1021 | proto.RegisterType((*DynamicPartitionGroup)(nil), "chromeos_update_engine.DynamicPartitionGroup") 1022 | proto.RegisterType((*DynamicPartitionMetadata)(nil), "chromeos_update_engine.DynamicPartitionMetadata") 1023 | proto.RegisterType((*DeltaArchiveManifest)(nil), "chromeos_update_engine.DeltaArchiveManifest") 1024 | } 1025 | 1026 | func init() { 1027 | proto.RegisterFile("update_metadata.proto", fileDescriptor_fa6d72a1ce634b79) 1028 | } 1029 | 1030 | var fileDescriptor_fa6d72a1ce634b79 = []byte{ 1031 | // 1334 bytes of a gzipped FileDescriptorProto 1032 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x57, 0x6d, 0x6f, 0x1b, 0xc5, 1033 | 0x13, 0xff, 0x9f, 0xed, 0xc4, 0xbe, 0xb1, 0xef, 0x7c, 0xd9, 0x36, 0xff, 0x1e, 0x15, 0x94, 0xe0, 1034 | 0xd2, 0x26, 0x08, 0x88, 0x4a, 0x04, 0x45, 0x54, 0x42, 0x28, 0x0f, 0x4e, 0x62, 0x91, 0xe0, 0xb0, 1035 | 0x4e, 0x0b, 0xf4, 0xcd, 0x69, 0xe3, 0x5b, 0xc7, 0xa7, 0xde, 0xed, 0x9e, 0x6e, 0xd7, 0x4d, 0xd3, 1036 | 0xcf, 0xc0, 0xc7, 0xe0, 0x2d, 0x2f, 0xf8, 0x28, 0xbc, 0x44, 0xe2, 0xc3, 0xa0, 0xdd, 0x7b, 0x74, 1037 | 0x69, 0x54, 0x9b, 0x77, 0xbb, 0xbf, 0x99, 0xf9, 0xed, 0xcc, 0xde, 0xcc, 0xec, 0x1c, 0xac, 0xcf, 1038 | 0x62, 0x9f, 0x48, 0xea, 0x45, 0x54, 0x12, 0x9f, 0x48, 0xb2, 0x1d, 0x27, 0x5c, 0x72, 0xf4, 0xff, 1039 | 0xf1, 0x34, 0xe1, 0x11, 0xe5, 0xc2, 0xcb, 0xe4, 0x94, 0x5d, 0x06, 0x8c, 0xf6, 0x8e, 0x61, 0xb5, 1040 | 0xff, 0x4a, 0x52, 0x26, 0xd1, 0x87, 0xd0, 0x16, 0x92, 0x24, 0xd2, 0xbb, 0x08, 0xf9, 0xf8, 0x85, 1041 | 0x6b, 0x6c, 0x18, 0x5b, 0x0d, 0x0c, 0x1a, 0xda, 0x53, 0x08, 0xfa, 0x00, 0x80, 0xcd, 0xa2, 0x54, 1042 | 0x2c, 0xdc, 0x9a, 0x96, 0x9b, 0x6c, 0x16, 0x69, 0xa9, 0xe8, 0xfd, 0x69, 0x00, 0x8c, 0x82, 0x4b, 1043 | 0x46, 0xe4, 0x2c, 0xa1, 0x02, 0x9d, 0x00, 0x88, 0x62, 0xe7, 0x1a, 0x1b, 0xf5, 0xad, 0xf6, 0xce, 1044 | 0x67, 0xdb, 0x6f, 0xf7, 0x62, 0xbb, 0xb4, 0x2b, 0x97, 0xb8, 0x62, 0x7f, 0x77, 0x06, 0x66, 0x21, 1045 | 0x40, 0xef, 0x43, 0xf3, 0x25, 0x4d, 0x44, 0xc0, 0x99, 0xf6, 0xd2, 0xda, 0xab, 0xb9, 0x06, 0xce, 1046 | 0x21, 0x84, 0xa0, 0xa1, 0xe2, 0xd6, 0x0e, 0x76, 0xb0, 0x5e, 0xa3, 0xc7, 0x70, 0x67, 0xc6, 0x62, 1047 | 0xe2, 0xfb, 0xd4, 0xf7, 0x0a, 0x56, 0x4f, 0x04, 0xaf, 0xa9, 0x5b, 0xdf, 0x30, 0xb6, 0x9a, 0x78, 1048 | 0x3d, 0x17, 0x17, 0xa7, 0x8c, 0x82, 0xd7, 0xb4, 0xf7, 0x35, 0x58, 0x67, 0x24, 0x91, 0x81, 0x0c, 1049 | 0x38, 0x1b, 0xb0, 0x09, 0x57, 0xe4, 0xda, 0x2a, 0xbd, 0x1d, 0xbd, 0x56, 0xd8, 0x94, 0x88, 0x69, 1050 | 0x7e, 0xa0, 0x5a, 0xf7, 0xfe, 0x30, 0xc0, 0x1c, 0x44, 0xe4, 0x92, 0x6a, 0xab, 0xdb, 0xb0, 0x72, 1051 | 0xc1, 0x49, 0xe2, 0x6b, 0x33, 0x13, 0xa7, 0x1b, 0xe4, 0x40, 0xfd, 0x05, 0xbd, 0xd6, 0x66, 0x26, 1052 | 0x56, 0x4b, 0xe4, 0x42, 0x73, 0x3c, 0x25, 0x8c, 0xd1, 0x50, 0xbb, 0x65, 0xe2, 0x7c, 0xab, 0x24, 1053 | 0x79, 0xc8, 0x8d, 0x54, 0x92, 0x87, 0x7b, 0x1f, 0xac, 0x8b, 0x59, 0x10, 0xfa, 0x5e, 0x6e, 0xb9, 1054 | 0xa2, 0xe5, 0x1d, 0x0d, 0xee, 0x67, 0xe6, 0x85, 0x52, 0x4e, 0xb2, 0x5a, 0x51, 0x7a, 0x96, 0x62, 1055 | 0xbd, 0xbf, 0x1a, 0xe0, 0x0c, 0x98, 0x90, 0x24, 0x0c, 0x87, 0x31, 0x4d, 0x88, 0x0a, 0x1a, 0xed, 1056 | 0x42, 0x43, 0x5e, 0xc7, 0x2a, 0xe0, 0xda, 0x96, 0xbd, 0xf3, 0xf9, 0x4d, 0x1f, 0xf0, 0x4d, 0xbb, 1057 | 0xed, 0xf3, 0xeb, 0x98, 0x62, 0x6d, 0xaa, 0x12, 0x4b, 0x7d, 0x04, 0x8f, 0x4f, 0x26, 0x82, 0xca, 1058 | 0x2c, 0x71, 0x40, 0x41, 0x43, 0x8d, 0x14, 0x0a, 0x21, 0x65, 0x97, 0x72, 0xaa, 0x43, 0xcf, 0x14, 1059 | 0x4e, 0x34, 0x82, 0xbe, 0x83, 0xb6, 0x48, 0xc6, 0x1e, 0xd5, 0x89, 0x2a, 0xdc, 0x86, 0x4e, 0xa6, 1060 | 0x7b, 0x37, 0xf9, 0x92, 0xe6, 0x33, 0x06, 0x91, 0x8c, 0xd3, 0xa5, 0x50, 0xa9, 0xab, 0x08, 0xb2, 1061 | 0x03, 0x56, 0xd2, 0xd4, 0x15, 0xc9, 0xb8, 0xe4, 0xf7, 0x85, 0x2c, 0xf8, 0x57, 0x17, 0xe3, 0xf7, 1062 | 0x85, 0xac, 0xf0, 0x2b, 0x82, 0x8c, 0xbf, 0x99, 0xf2, 0xfb, 0x42, 0x66, 0xfc, 0x5b, 0xe0, 0xe8, 1063 | 0x00, 0xc5, 0x94, 0xec, 0x7c, 0xf5, 0xd8, 0xd3, 0xd9, 0xd2, 0xd2, 0xd9, 0x62, 0x2b, 0x7c, 0xa4, 1064 | 0xe1, 0x63, 0x22, 0xa6, 0xe8, 0x21, 0x74, 0x95, 0xa3, 0x55, 0x45, 0x53, 0x2b, 0x5a, 0x22, 0x19, 1065 | 0x97, 0x7a, 0xbd, 0xdf, 0x0d, 0x68, 0xa8, 0x2b, 0x46, 0x6d, 0x68, 0xe2, 0xfe, 0xd9, 0xc9, 0xee, 1066 | 0x7e, 0xdf, 0xf9, 0x1f, 0xb2, 0x01, 0xb2, 0x8d, 0xb7, 0xf7, 0xdc, 0x31, 0x50, 0x07, 0x1a, 0xa7, 1067 | 0xc3, 0x67, 0x7d, 0xa7, 0x76, 0xb7, 0xd6, 0x32, 0x90, 0x0d, 0xab, 0x7b, 0xa3, 0x83, 0xc1, 0xe1, 1068 | 0xa1, 0x53, 0xd7, 0xfb, 0x2e, 0xb4, 0x47, 0xc3, 0xa7, 0x78, 0xbf, 0xef, 0xed, 0x0f, 0xcf, 0x7e, 1069 | 0x71, 0x1a, 0x68, 0x0d, 0xac, 0x0c, 0xc8, 0xf4, 0x56, 0xaa, 0x8c, 0x3f, 0x3f, 0x77, 0x5a, 0xa8, 1070 | 0x05, 0x8d, 0xe7, 0x7d, 0x3c, 0x74, 0x56, 0xd5, 0xc1, 0x07, 0x83, 0xd1, 0xfe, 0x2e, 0x3e, 0x70, 1071 | 0x9a, 0xca, 0x72, 0x0f, 0x0f, 0xcf, 0x4f, 0x06, 0xb9, 0x25, 0xa0, 0x0e, 0xb4, 0xce, 0x9e, 0x1e, 1072 | 0x1e, 0xea, 0x9d, 0xd9, 0xfb, 0xbb, 0x09, 0xdd, 0xa2, 0x92, 0x9e, 0xea, 0xeb, 0x44, 0x0f, 0xc0, 1073 | 0x8e, 0x73, 0xc8, 0x63, 0x24, 0x4a, 0x93, 0xcc, 0xc4, 0x56, 0x81, 0xfe, 0x40, 0x22, 0x8a, 0x36, 1074 | 0xa1, 0x9b, 0xcc, 0x98, 0x17, 0x73, 0x21, 0x83, 0x34, 0xcb, 0x74, 0x0a, 0xb5, 0xb0, 0x9d, 0xcc, 1075 | 0xd8, 0x59, 0x89, 0xa2, 0x4f, 0xc0, 0xa9, 0x28, 0x79, 0x31, 0xc9, 0x72, 0xc9, 0xc4, 0xdd, 0x0a, 1076 | 0x7e, 0x46, 0xe4, 0x54, 0x71, 0x4e, 0x82, 0x90, 0x8a, 0x6b, 0x21, 0x69, 0xe4, 0xe9, 0x04, 0x4f, 1077 | 0xcb, 0xca, 0x2e, 0x61, 0x7d, 0xbd, 0x3e, 0xdc, 0x61, 0xf4, 0xca, 0x2b, 0xfd, 0x2c, 0xba, 0x87, 1078 | 0xbb, 0xf2, 0x1f, 0x5a, 0xda, 0x3a, 0xa3, 0x57, 0xc5, 0x35, 0x94, 0x0d, 0x6d, 0x04, 0x88, 0x87, 1079 | 0x7e, 0xe5, 0x94, 0x80, 0x4d, 0xb8, 0xae, 0xd1, 0xf6, 0xce, 0x83, 0x9b, 0x0e, 0x98, 0x6b, 0x4c, 1080 | 0xd8, 0xe1, 0xa1, 0x3f, 0xdf, 0xaa, 0x46, 0x80, 0xe6, 0x5d, 0xd7, 0xa4, 0xcd, 0xa5, 0x48, 0xab, 1081 | 0xee, 0x6a, 0xd2, 0x63, 0x00, 0x9e, 0xd7, 0xb8, 0x70, 0x5b, 0xfa, 0x0a, 0xb6, 0x16, 0x6d, 0x0a, 1082 | 0xb8, 0x62, 0x8b, 0xbe, 0x80, 0xdb, 0xd5, 0xaf, 0xc5, 0x63, 0x05, 0x93, 0x50, 0xa7, 0x7b, 0x0b, 1083 | 0xdf, 0xaa, 0xc8, 0x86, 0x99, 0x08, 0xfd, 0x08, 0xeb, 0xaa, 0x22, 0x3c, 0x99, 0x50, 0xea, 0xe9, 1084 | 0x82, 0x4a, 0x2b, 0xd6, 0x05, 0x1d, 0xd4, 0xbb, 0x0a, 0x16, 0x29, 0xe3, 0xf3, 0x84, 0xd2, 0x03, 1085 | 0x22, 0x49, 0xf6, 0xe8, 0x1d, 0x83, 0x53, 0x52, 0x66, 0x6c, 0xed, 0x85, 0xd8, 0xec, 0x9c, 0x2d, 1086 | 0x63, 0xda, 0x86, 0x5b, 0x25, 0x13, 0x09, 0x2f, 0x79, 0x12, 0xc8, 0x69, 0xe4, 0x76, 0x74, 0x5a, 1087 | 0xad, 0xe5, 0xca, 0xbb, 0xb9, 0x00, 0x7d, 0x0c, 0x76, 0xa9, 0x2f, 0x48, 0x28, 0x5d, 0x4b, 0x17, 1088 | 0x7a, 0x27, 0x57, 0x1d, 0x91, 0x50, 0xa2, 0x43, 0xe8, 0x4e, 0xe8, 0x78, 0x2e, 0x58, 0x7b, 0x21, 1089 | 0xf7, 0xac, 0x09, 0x1d, 0x57, 0xe2, 0xfc, 0x16, 0x40, 0xf1, 0x64, 0x14, 0xdd, 0x85, 0x28, 0xcc, 1090 | 0x09, 0xcd, 0x1a, 0x28, 0xba, 0x07, 0x6a, 0xe3, 0x25, 0x9c, 0x4b, 0xe1, 0x3a, 0xea, 0xcd, 0x7d, 1091 | 0x62, 0xec, 0xe0, 0xd6, 0x84, 0x8e, 0xb1, 0x82, 0x7a, 0x53, 0x58, 0x3f, 0xb8, 0x66, 0x24, 0x0a, 1092 | 0xc6, 0x45, 0xba, 0x1c, 0x25, 0x7c, 0x16, 0xab, 0xb7, 0xb1, 0x52, 0xd9, 0x7a, 0x5d, 0xbc, 0xa1, 1093 | 0xb5, 0xca, 0x1b, 0xba, 0x09, 0xdd, 0xf9, 0x5e, 0x20, 0xdc, 0xfa, 0x46, 0x5d, 0x15, 0xe4, 0x5c, 1094 | 0x33, 0x10, 0xbd, 0x5f, 0x0d, 0x70, 0xdf, 0x3c, 0xea, 0x34, 0x1b, 0x75, 0x50, 0x1f, 0x56, 0x2f, 1095 | 0xd5, 0xb1, 0xf9, 0xbc, 0x71, 0xe3, 0x73, 0xf5, 0x56, 0x67, 0x71, 0x66, 0xac, 0x1a, 0x89, 0x60, 1096 | 0x24, 0x16, 0x53, 0x2e, 0x3d, 0xca, 0xc8, 0x45, 0x48, 0xfd, 0xac, 0xe5, 0x74, 0x73, 0xbc, 0x9f, 1097 | 0xc2, 0xbd, 0xdf, 0x5a, 0x70, 0xfb, 0x80, 0x86, 0x92, 0xec, 0x26, 0xe3, 0x69, 0xf0, 0x92, 0x9e, 1098 | 0x12, 0x16, 0x4c, 0xa8, 0x90, 0xe8, 0x27, 0x40, 0x65, 0x6a, 0x17, 0x05, 0x63, 0x2c, 0x59, 0x30, 1099 | 0x6b, 0xc1, 0x1b, 0x88, 0x40, 0x3e, 0xbc, 0xf7, 0x82, 0x26, 0x8c, 0x86, 0xde, 0x5b, 0xf8, 0x6b, 1100 | 0x4b, 0xf2, 0xdf, 0x49, 0xa9, 0x06, 0xff, 0x3a, 0xe5, 0x3e, 0x80, 0x9e, 0xf3, 0xca, 0x19, 0xc9, 1101 | 0x7a, 0xd2, 0xf8, 0xf2, 0xd1, 0x37, 0x8f, 0xb1, 0xa9, 0x71, 0x35, 0x1d, 0xa1, 0x4f, 0x61, 0xad, 1102 | 0x1c, 0xd1, 0xf2, 0xe7, 0xbd, 0xa1, 0xbf, 0xaa, 0x53, 0x0a, 0xb2, 0x47, 0x7e, 0x13, 0xba, 0x15, 1103 | 0x65, 0x4d, 0x9b, 0xbe, 0xc3, 0x76, 0x09, 0x6b, 0xd6, 0x53, 0xe8, 0xaa, 0x66, 0x58, 0x04, 0xb9, 1104 | 0x6c, 0x27, 0xb4, 0x78, 0xe8, 0x7f, 0x9f, 0x85, 0x35, 0xe1, 0x8a, 0x4e, 0xb5, 0xc1, 0x2a, 0xdd, 1105 | 0x52, 0x3d, 0xd0, 0x62, 0xf4, 0x6a, 0x9e, 0x4e, 0x79, 0xa7, 0x2a, 0x61, 0x22, 0x52, 0xba, 0xd6, 1106 | 0xb2, 0xde, 0x61, 0x6d, 0x5c, 0xf5, 0xae, 0x4a, 0x67, 0x2e, 0xeb, 0x5d, 0x85, 0xee, 0x08, 0x6c, 1107 | 0xe5, 0x5d, 0xa0, 0x26, 0xcf, 0x94, 0x2d, 0x6d, 0x8d, 0x1f, 0xdd, 0x98, 0x11, 0xf9, 0x8c, 0x8a, 1108 | 0x3b, 0x3c, 0xf4, 0xcb, 0x89, 0xf5, 0x08, 0x6c, 0xe5, 0x57, 0x85, 0xa8, 0xbd, 0x30, 0x11, 0xa3, 1109 | 0x57, 0x25, 0xd1, 0x43, 0xb0, 0xa2, 0x80, 0xf1, 0xa4, 0x98, 0x3c, 0x3b, 0x69, 0xf7, 0x78, 0x84, 1110 | 0x3b, 0x1a, 0xcf, 0x86, 0x4f, 0x74, 0x04, 0x50, 0x54, 0xba, 0x70, 0x2d, 0x9d, 0xc7, 0x9b, 0xef, 1111 | 0xbc, 0x83, 0x74, 0x92, 0xc0, 0x15, 0x53, 0x35, 0xea, 0x46, 0xe4, 0x95, 0x27, 0x83, 0x88, 0x0a, 1112 | 0x49, 0xa2, 0x58, 0xf7, 0xcb, 0x3a, 0xee, 0x44, 0xe4, 0xd5, 0x79, 0x8e, 0x21, 0x06, 0x77, 0xfd, 1113 | 0xb4, 0x05, 0x54, 0xde, 0xc7, 0xfc, 0x8f, 0x29, 0x6b, 0x8f, 0x8f, 0x16, 0x6d, 0x1e, 0x79, 0xfb, 1114 | 0xc1, 0xae, 0x7f, 0x83, 0x64, 0xaf, 0x76, 0x5c, 0xff, 0x27, 0x00, 0x00, 0xff, 0xff, 0x83, 0x60, 1115 | 0xd1, 0x89, 0x99, 0x0d, 0x00, 0x00, 1116 | } 1117 | --------------------------------------------------------------------------------