mirror of
https://github.com/reactos/syzkaller.git
synced 2024-12-11 05:13:52 +00:00
a7b199253f
Currently we have unix permissions for new files/dirs hardcoded throughout the code base. Some places use 0644, some - 0640, some - 0600 and a variety of other constants. Introduce osutil.MkdirAll/WriteFile that use the default permissions and use them throughout the code base. This makes permissions consistent and also allows to easily change the permissions later if we change our minds. Also merge pkg/fileutil into pkg/osutil as they become dependent on each other. The line between them was poorly defined anyway as both operate on files.
113 lines
3.0 KiB
Go
113 lines
3.0 KiB
Go
// Copyright 2017 syzkaller project authors. All rights reserved.
|
|
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
|
|
|
|
package config
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"reflect"
|
|
"strings"
|
|
|
|
"github.com/google/syzkaller/pkg/osutil"
|
|
)
|
|
|
|
func LoadFile(filename string, cfg interface{}) error {
|
|
if filename == "" {
|
|
return fmt.Errorf("no config file specified")
|
|
}
|
|
data, err := ioutil.ReadFile(filename)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to read config file: %v", err)
|
|
}
|
|
return LoadData(data, cfg)
|
|
}
|
|
|
|
func LoadData(data []byte, cfg interface{}) error {
|
|
if err := checkUnknownFields(data, reflect.ValueOf(cfg).Type()); err != nil {
|
|
return err
|
|
}
|
|
if err := json.Unmarshal(data, cfg); err != nil {
|
|
return fmt.Errorf("failed to parse config file: %v", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func SaveFile(filename string, cfg interface{}) error {
|
|
data, err := json.MarshalIndent(cfg, "", "\t")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return osutil.WriteFile(filename, data)
|
|
}
|
|
|
|
func checkUnknownFields(data []byte, typ reflect.Type) error {
|
|
if typ.Kind() != reflect.Ptr || typ.Elem().Kind() != reflect.Struct {
|
|
return fmt.Errorf("config type is not pointer to struct")
|
|
}
|
|
return checkUnknownFieldsRec(data, "", typ)
|
|
}
|
|
|
|
func checkUnknownFieldsRec(data []byte, prefix string, typ reflect.Type) error {
|
|
if typ.Kind() == reflect.Ptr {
|
|
typ = typ.Elem()
|
|
}
|
|
if typ.Kind() != reflect.Struct {
|
|
return fmt.Errorf("config type is not pointer to struct")
|
|
}
|
|
fields := make(map[string]reflect.Type)
|
|
for i := 0; i < typ.NumField(); i++ {
|
|
field := typ.Field(i)
|
|
if field.Tag.Get("json") == "-" {
|
|
continue
|
|
}
|
|
fields[strings.ToLower(field.Name)] = field.Type
|
|
}
|
|
f := make(map[string]interface{})
|
|
if err := json.Unmarshal(data, &f); err != nil {
|
|
return fmt.Errorf("failed to parse config file: %v", err)
|
|
}
|
|
for k, v := range f {
|
|
field, ok := fields[strings.ToLower(k)]
|
|
if !ok {
|
|
return fmt.Errorf("unknown field '%v%v' in config", prefix, k)
|
|
}
|
|
if v != nil && field.Kind() == reflect.Slice &&
|
|
(field.PkgPath() != "encoding/json" || field.Name() != "RawMessage") {
|
|
vv := reflect.ValueOf(v)
|
|
if vv.Type().Kind() != reflect.Slice {
|
|
return fmt.Errorf("bad json array type '%v%v'", prefix, k)
|
|
}
|
|
for i := 0; i < vv.Len(); i++ {
|
|
e := vv.Index(i).Interface()
|
|
prefix1 := fmt.Sprintf("%v%v[%v].", prefix, k, i)
|
|
if err := checkUnknownFieldsStruct(e, prefix1, field.Elem()); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
if err := checkUnknownFieldsStruct(v, prefix+k+".", field); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func checkUnknownFieldsStruct(val interface{}, prefix string, typ reflect.Type) error {
|
|
if typ.Kind() == reflect.Ptr {
|
|
typ = typ.Elem()
|
|
}
|
|
if typ.Kind() != reflect.Struct {
|
|
return nil
|
|
}
|
|
if typ.PkgPath() == "time" && typ.Name() == "Time" {
|
|
return nil
|
|
}
|
|
inner, err := json.Marshal(val)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to marshal inner struct '%v%v':", prefix, err)
|
|
}
|
|
return checkUnknownFieldsRec(inner, prefix, typ)
|
|
}
|