blob: 39d6f36ecc6fad17a7cd2926c37478db8320f5cc [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package system_updater
import (
"fmt"
"io/ioutil"
"os"
"syscall"
"syscall/zx/fdio"
zxio "syscall/zx/io"
fuchsiaio "fidl/fuchsia/io"
)
// UpdatePackage represents a handle to the update package.
type UpdatePackage struct {
dir *os.File
}
// NewUpdatePackage creates an UpdatePackage from a fidl interface
func NewUpdatePackage(proxy *fuchsiaio.DirectoryWithCtxInterface) (*UpdatePackage, error) {
updateDir := fdio.NewDirectoryWithCtx((*zxio.DirectoryAdminWithCtxInterface)(proxy))
updateDirFile := os.NewFile(uintptr(syscall.OpenFDIO(updateDir)), "update")
return &UpdatePackage{dir: updateDirFile}, nil
}
// Open a file from the update package for reading
func (p *UpdatePackage) Open(path string) (*os.File, error) {
dirFd := p.dir.Fd()
fileFd, err := syscall.OpenAt(int(dirFd), path, os.O_RDONLY, 0)
if err != nil {
return nil, err
}
return os.NewFile(uintptr(fileFd), path), nil
}
// Returns the files in the update package.
func (p *UpdatePackage) ListFiles() ([]string, error) {
// Readdirnames() leaves the file offset where it finishes, make sure to
// reset it before exiting.
names, err := p.dir.Readdirnames(0)
if err != nil {
// Best-effort attempt to reset the directory but don't let it clobber
// the original error.
_, _ = p.dir.Seek(0, 0)
return nil, fmt.Errorf("Failed to read directory: %s", err)
}
_, err = p.dir.Seek(0, 0)
if err != nil {
return nil, fmt.Errorf("Failed to reset directory: %s", err)
}
return names, nil
}
// ReadFile opens and reads a whole file from the update package
func (p *UpdatePackage) ReadFile(path string) ([]byte, error) {
f, err := p.Open(path)
if err != nil {
return nil, err
}
defer f.Close()
b, err := ioutil.ReadAll(f)
if err != nil {
return nil, err
}
return b, nil
}
// Stat a file from the update package
func (p *UpdatePackage) Stat(path string) (os.FileInfo, error) {
f, err := p.Open(path)
if err != nil {
return nil, err
}
defer f.Close()
return f.Stat()
}
// Merkleroot of the update package
func (p *UpdatePackage) Merkleroot() (string, error) {
b, err := p.ReadFile("meta")
if err != nil {
return "", err
}
merkle := string(b)
return merkle, nil
}
// Close the handle to the UpdatePackage.
func (p *UpdatePackage) Close() error {
err := p.dir.Close()
p.dir = nil
return err
}