blob: f96bd323113771a777694b2b215b298629ed1485 [file] [log] [blame] [edit]
// Copyright 2021 Google LLC
//
// 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 sysapi
import (
"bytes"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"syscall"
"time"
)
// Implementation of APIHandler interface.
type apiHandler struct {
}
// NewHandler creates a new APIHandler for use on any machine.
func NewHandler() (APIHandler, error) {
return new(apiHandler), nil
}
// ReadFile reads the named file and returns the content.
func (h *apiHandler) ReadFile(fileName string) ([]byte, error) {
return ioutil.ReadFile(fileName)
}
// WriteFile writes the given content to the named file.
func (h *apiHandler) WriteFile(name string, content []byte, perm os.FileMode) error {
return ioutil.WriteFile(name, content, perm)
}
// AtomicWriteFile atomically writes a file.
func (h *apiHandler) AtomicWriteFile(name string, content []byte,
perm os.FileMode) error {
// Write to a temporary file in the same directory first. This is to
// guarantee the the temporary file and the intended file are on the
// same filesystem.
dir := filepath.Dir(name)
tmpFile, err := ioutil.TempFile(dir, "atom_write")
if err != nil {
return err
}
// Write the file. os.Write() is guaranteed to return a non-nil error
// when the number of bytes written != len(content).
_, err = tmpFile.Write(content)
if err1 := tmpFile.Close(); err == nil {
err = err1
}
if err != nil {
os.Remove(tmpFile.Name())
return err
}
// Rename the temporary file to the desired name. This is an atomic
// operation on POSIX compliant file systems.
return syscall.Rename(tmpFile.Name(), name)
}
// RunCommand returns the stdout and stderr produced by running the named
// program with the given arguments.
func (h *apiHandler) RunCommand(name string, args ...string) ([]byte, []byte, error) {
cmd := exec.Command(name, args...)
var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
if err := cmd.Run(); err != nil {
return nil, nil, err
}
return stdout.Bytes(), stderr.Bytes(), nil
}
// MkdirAll creates a directory named path, along with any necessary parents,
// and returns nil, or else returns an error. The permission bits perm are used
// for all directories that MkdirAll creates. If path is already a directory,
// MkdirAll does nothing and returns nil.
func (h *apiHandler) MkdirAll(path string, perm os.FileMode) error {
return os.MkdirAll(path, perm)
}
// FileExists checks if the named file exists.
func (h *apiHandler) FileExists(path string) bool {
if _, err := os.Stat(path); os.IsNotExist(err) {
return false
}
return true
}
// GetUnixTimestamp returns the current UNIX timestamp.
func (h *apiHandler) GetUnixTimestamp() int64 {
return time.Now().Unix()
}