diff options
Diffstat (limited to 'vendor/github.com/d5/tengo/v2/stdlib/os.go')
-rw-r--r-- | vendor/github.com/d5/tengo/v2/stdlib/os.go | 564 |
1 files changed, 564 insertions, 0 deletions
diff --git a/vendor/github.com/d5/tengo/v2/stdlib/os.go b/vendor/github.com/d5/tengo/v2/stdlib/os.go new file mode 100644 index 00000000..576bc94b --- /dev/null +++ b/vendor/github.com/d5/tengo/v2/stdlib/os.go @@ -0,0 +1,564 @@ +package stdlib + +import ( + "fmt" + "io" + "io/ioutil" + "os" + "os/exec" + + "github.com/d5/tengo/v2" +) + +var osModule = map[string]tengo.Object{ + "o_rdonly": &tengo.Int{Value: int64(os.O_RDONLY)}, + "o_wronly": &tengo.Int{Value: int64(os.O_WRONLY)}, + "o_rdwr": &tengo.Int{Value: int64(os.O_RDWR)}, + "o_append": &tengo.Int{Value: int64(os.O_APPEND)}, + "o_create": &tengo.Int{Value: int64(os.O_CREATE)}, + "o_excl": &tengo.Int{Value: int64(os.O_EXCL)}, + "o_sync": &tengo.Int{Value: int64(os.O_SYNC)}, + "o_trunc": &tengo.Int{Value: int64(os.O_TRUNC)}, + "mode_dir": &tengo.Int{Value: int64(os.ModeDir)}, + "mode_append": &tengo.Int{Value: int64(os.ModeAppend)}, + "mode_exclusive": &tengo.Int{Value: int64(os.ModeExclusive)}, + "mode_temporary": &tengo.Int{Value: int64(os.ModeTemporary)}, + "mode_symlink": &tengo.Int{Value: int64(os.ModeSymlink)}, + "mode_device": &tengo.Int{Value: int64(os.ModeDevice)}, + "mode_named_pipe": &tengo.Int{Value: int64(os.ModeNamedPipe)}, + "mode_socket": &tengo.Int{Value: int64(os.ModeSocket)}, + "mode_setuid": &tengo.Int{Value: int64(os.ModeSetuid)}, + "mode_setgui": &tengo.Int{Value: int64(os.ModeSetgid)}, + "mode_char_device": &tengo.Int{Value: int64(os.ModeCharDevice)}, + "mode_sticky": &tengo.Int{Value: int64(os.ModeSticky)}, + "mode_type": &tengo.Int{Value: int64(os.ModeType)}, + "mode_perm": &tengo.Int{Value: int64(os.ModePerm)}, + "path_separator": &tengo.Char{Value: os.PathSeparator}, + "path_list_separator": &tengo.Char{Value: os.PathListSeparator}, + "dev_null": &tengo.String{Value: os.DevNull}, + "seek_set": &tengo.Int{Value: int64(io.SeekStart)}, + "seek_cur": &tengo.Int{Value: int64(io.SeekCurrent)}, + "seek_end": &tengo.Int{Value: int64(io.SeekEnd)}, + "args": &tengo.UserFunction{ + Name: "args", + Value: osArgs, + }, // args() => array(string) + "chdir": &tengo.UserFunction{ + Name: "chdir", + Value: FuncASRE(os.Chdir), + }, // chdir(dir string) => error + "chmod": osFuncASFmRE("chmod", os.Chmod), // chmod(name string, mode int) => error + "chown": &tengo.UserFunction{ + Name: "chown", + Value: FuncASIIRE(os.Chown), + }, // chown(name string, uid int, gid int) => error + "clearenv": &tengo.UserFunction{ + Name: "clearenv", + Value: FuncAR(os.Clearenv), + }, // clearenv() + "environ": &tengo.UserFunction{ + Name: "environ", + Value: FuncARSs(os.Environ), + }, // environ() => array(string) + "exit": &tengo.UserFunction{ + Name: "exit", + Value: FuncAIR(os.Exit), + }, // exit(code int) + "expand_env": &tengo.UserFunction{ + Name: "expand_env", + Value: osExpandEnv, + }, // expand_env(s string) => string + "getegid": &tengo.UserFunction{ + Name: "getegid", + Value: FuncARI(os.Getegid), + }, // getegid() => int + "getenv": &tengo.UserFunction{ + Name: "getenv", + Value: FuncASRS(os.Getenv), + }, // getenv(s string) => string + "geteuid": &tengo.UserFunction{ + Name: "geteuid", + Value: FuncARI(os.Geteuid), + }, // geteuid() => int + "getgid": &tengo.UserFunction{ + Name: "getgid", + Value: FuncARI(os.Getgid), + }, // getgid() => int + "getgroups": &tengo.UserFunction{ + Name: "getgroups", + Value: FuncARIsE(os.Getgroups), + }, // getgroups() => array(string)/error + "getpagesize": &tengo.UserFunction{ + Name: "getpagesize", + Value: FuncARI(os.Getpagesize), + }, // getpagesize() => int + "getpid": &tengo.UserFunction{ + Name: "getpid", + Value: FuncARI(os.Getpid), + }, // getpid() => int + "getppid": &tengo.UserFunction{ + Name: "getppid", + Value: FuncARI(os.Getppid), + }, // getppid() => int + "getuid": &tengo.UserFunction{ + Name: "getuid", + Value: FuncARI(os.Getuid), + }, // getuid() => int + "getwd": &tengo.UserFunction{ + Name: "getwd", + Value: FuncARSE(os.Getwd), + }, // getwd() => string/error + "hostname": &tengo.UserFunction{ + Name: "hostname", + Value: FuncARSE(os.Hostname), + }, // hostname() => string/error + "lchown": &tengo.UserFunction{ + Name: "lchown", + Value: FuncASIIRE(os.Lchown), + }, // lchown(name string, uid int, gid int) => error + "link": &tengo.UserFunction{ + Name: "link", + Value: FuncASSRE(os.Link), + }, // link(oldname string, newname string) => error + "lookup_env": &tengo.UserFunction{ + Name: "lookup_env", + Value: osLookupEnv, + }, // lookup_env(key string) => string/false + "mkdir": osFuncASFmRE("mkdir", os.Mkdir), // mkdir(name string, perm int) => error + "mkdir_all": osFuncASFmRE("mkdir_all", os.MkdirAll), // mkdir_all(name string, perm int) => error + "readlink": &tengo.UserFunction{ + Name: "readlink", + Value: FuncASRSE(os.Readlink), + }, // readlink(name string) => string/error + "remove": &tengo.UserFunction{ + Name: "remove", + Value: FuncASRE(os.Remove), + }, // remove(name string) => error + "remove_all": &tengo.UserFunction{ + Name: "remove_all", + Value: FuncASRE(os.RemoveAll), + }, // remove_all(name string) => error + "rename": &tengo.UserFunction{ + Name: "rename", + Value: FuncASSRE(os.Rename), + }, // rename(oldpath string, newpath string) => error + "setenv": &tengo.UserFunction{ + Name: "setenv", + Value: FuncASSRE(os.Setenv), + }, // setenv(key string, value string) => error + "symlink": &tengo.UserFunction{ + Name: "symlink", + Value: FuncASSRE(os.Symlink), + }, // symlink(oldname string newname string) => error + "temp_dir": &tengo.UserFunction{ + Name: "temp_dir", + Value: FuncARS(os.TempDir), + }, // temp_dir() => string + "truncate": &tengo.UserFunction{ + Name: "truncate", + Value: FuncASI64RE(os.Truncate), + }, // truncate(name string, size int) => error + "unsetenv": &tengo.UserFunction{ + Name: "unsetenv", + Value: FuncASRE(os.Unsetenv), + }, // unsetenv(key string) => error + "create": &tengo.UserFunction{ + Name: "create", + Value: osCreate, + }, // create(name string) => imap(file)/error + "open": &tengo.UserFunction{ + Name: "open", + Value: osOpen, + }, // open(name string) => imap(file)/error + "open_file": &tengo.UserFunction{ + Name: "open_file", + Value: osOpenFile, + }, // open_file(name string, flag int, perm int) => imap(file)/error + "find_process": &tengo.UserFunction{ + Name: "find_process", + Value: osFindProcess, + }, // find_process(pid int) => imap(process)/error + "start_process": &tengo.UserFunction{ + Name: "start_process", + Value: osStartProcess, + }, // start_process(name string, argv array(string), dir string, env array(string)) => imap(process)/error + "exec_look_path": &tengo.UserFunction{ + Name: "exec_look_path", + Value: FuncASRSE(exec.LookPath), + }, // exec_look_path(file) => string/error + "exec": &tengo.UserFunction{ + Name: "exec", + Value: osExec, + }, // exec(name, args...) => command + "stat": &tengo.UserFunction{ + Name: "stat", + Value: osStat, + }, // stat(name) => imap(fileinfo)/error + "read_file": &tengo.UserFunction{ + Name: "read_file", + Value: osReadFile, + }, // readfile(name) => array(byte)/error +} + +func osReadFile(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 1 { + return nil, tengo.ErrWrongNumArguments + } + fname, ok := tengo.ToString(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + } + bytes, err := ioutil.ReadFile(fname) + if err != nil { + return wrapError(err), nil + } + if len(bytes) > tengo.MaxBytesLen { + return nil, tengo.ErrBytesLimit + } + return &tengo.Bytes{Value: bytes}, nil +} + +func osStat(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 1 { + return nil, tengo.ErrWrongNumArguments + } + fname, ok := tengo.ToString(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + } + stat, err := os.Stat(fname) + if err != nil { + return wrapError(err), nil + } + fstat := &tengo.ImmutableMap{ + Value: map[string]tengo.Object{ + "name": &tengo.String{Value: stat.Name()}, + "mtime": &tengo.Time{Value: stat.ModTime()}, + "size": &tengo.Int{Value: stat.Size()}, + "mode": &tengo.Int{Value: int64(stat.Mode())}, + }, + } + if stat.IsDir() { + fstat.Value["directory"] = tengo.TrueValue + } else { + fstat.Value["directory"] = tengo.FalseValue + } + return fstat, nil +} + +func osCreate(args ...tengo.Object) (tengo.Object, error) { + if len(args) != 1 { + return nil, tengo.ErrWrongNumArguments + } + s1, ok := tengo.ToString(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + } + res, err := os.Create(s1) + if err != nil { + return wrapError(err), nil + } + return makeOSFile(res), nil +} + +func osOpen(args ...tengo.Object) (tengo.Object, error) { + if len(args) != 1 { + return nil, tengo.ErrWrongNumArguments + } + s1, ok := tengo.ToString(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + } + res, err := os.Open(s1) + if err != nil { + return wrapError(err), nil + } + return makeOSFile(res), nil +} + +func osOpenFile(args ...tengo.Object) (tengo.Object, error) { + if len(args) != 3 { + return nil, tengo.ErrWrongNumArguments + } + s1, ok := tengo.ToString(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + } + i2, ok := tengo.ToInt(args[1]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "int(compatible)", + Found: args[1].TypeName(), + } + } + i3, ok := tengo.ToInt(args[2]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "third", + Expected: "int(compatible)", + Found: args[2].TypeName(), + } + } + res, err := os.OpenFile(s1, i2, os.FileMode(i3)) + if err != nil { + return wrapError(err), nil + } + return makeOSFile(res), nil +} + +func osArgs(args ...tengo.Object) (tengo.Object, error) { + if len(args) != 0 { + return nil, tengo.ErrWrongNumArguments + } + arr := &tengo.Array{} + for _, osArg := range os.Args { + if len(osArg) > tengo.MaxStringLen { + return nil, tengo.ErrStringLimit + } + arr.Value = append(arr.Value, &tengo.String{Value: osArg}) + } + return arr, nil +} + +func osFuncASFmRE( + name string, + fn func(string, os.FileMode) error, +) *tengo.UserFunction { + return &tengo.UserFunction{ + Name: name, + Value: func(args ...tengo.Object) (tengo.Object, error) { + if len(args) != 2 { + return nil, tengo.ErrWrongNumArguments + } + s1, ok := tengo.ToString(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + } + i2, ok := tengo.ToInt64(args[1]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "int(compatible)", + Found: args[1].TypeName(), + } + } + return wrapError(fn(s1, os.FileMode(i2))), nil + }, + } +} + +func osLookupEnv(args ...tengo.Object) (tengo.Object, error) { + if len(args) != 1 { + return nil, tengo.ErrWrongNumArguments + } + s1, ok := tengo.ToString(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + } + res, ok := os.LookupEnv(s1) + if !ok { + return tengo.FalseValue, nil + } + if len(res) > tengo.MaxStringLen { + return nil, tengo.ErrStringLimit + } + return &tengo.String{Value: res}, nil +} + +func osExpandEnv(args ...tengo.Object) (tengo.Object, error) { + if len(args) != 1 { + return nil, tengo.ErrWrongNumArguments + } + s1, ok := tengo.ToString(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + } + var vlen int + var failed bool + s := os.Expand(s1, func(k string) string { + if failed { + return "" + } + v := os.Getenv(k) + + // this does not count the other texts that are not being replaced + // but the code checks the final length at the end + vlen += len(v) + if vlen > tengo.MaxStringLen { + failed = true + return "" + } + return v + }) + if failed || len(s) > tengo.MaxStringLen { + return nil, tengo.ErrStringLimit + } + return &tengo.String{Value: s}, nil +} + +func osExec(args ...tengo.Object) (tengo.Object, error) { + if len(args) == 0 { + return nil, tengo.ErrWrongNumArguments + } + name, ok := tengo.ToString(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + } + var execArgs []string + for idx, arg := range args[1:] { + execArg, ok := tengo.ToString(arg) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: fmt.Sprintf("args[%d]", idx), + Expected: "string(compatible)", + Found: args[1+idx].TypeName(), + } + } + execArgs = append(execArgs, execArg) + } + return makeOSExecCommand(exec.Command(name, execArgs...)), nil +} + +func osFindProcess(args ...tengo.Object) (tengo.Object, error) { + if len(args) != 1 { + return nil, tengo.ErrWrongNumArguments + } + i1, ok := tengo.ToInt(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "int(compatible)", + Found: args[0].TypeName(), + } + } + proc, err := os.FindProcess(i1) + if err != nil { + return wrapError(err), nil + } + return makeOSProcess(proc), nil +} + +func osStartProcess(args ...tengo.Object) (tengo.Object, error) { + if len(args) != 4 { + return nil, tengo.ErrWrongNumArguments + } + name, ok := tengo.ToString(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + } + var argv []string + var err error + switch arg1 := args[1].(type) { + case *tengo.Array: + argv, err = stringArray(arg1.Value, "second") + if err != nil { + return nil, err + } + case *tengo.ImmutableArray: + argv, err = stringArray(arg1.Value, "second") + if err != nil { + return nil, err + } + default: + return nil, tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "array", + Found: arg1.TypeName(), + } + } + + dir, ok := tengo.ToString(args[2]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "third", + Expected: "string(compatible)", + Found: args[2].TypeName(), + } + } + + var env []string + switch arg3 := args[3].(type) { + case *tengo.Array: + env, err = stringArray(arg3.Value, "fourth") + if err != nil { + return nil, err + } + case *tengo.ImmutableArray: + env, err = stringArray(arg3.Value, "fourth") + if err != nil { + return nil, err + } + default: + return nil, tengo.ErrInvalidArgumentType{ + Name: "fourth", + Expected: "array", + Found: arg3.TypeName(), + } + } + + proc, err := os.StartProcess(name, argv, &os.ProcAttr{ + Dir: dir, + Env: env, + }) + if err != nil { + return wrapError(err), nil + } + return makeOSProcess(proc), nil +} + +func stringArray(arr []tengo.Object, argName string) ([]string, error) { + var sarr []string + for idx, elem := range arr { + str, ok := elem.(*tengo.String) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: fmt.Sprintf("%s[%d]", argName, idx), + Expected: "string", + Found: elem.TypeName(), + } + } + sarr = append(sarr, str.Value) + } + return sarr, nil +} |