From 660e17071e4683148f154fd4336ab25732e6f6c9 Mon Sep 17 00:00:00 2001 From: Larry Clapp Date: Fri, 28 Jun 2024 09:26:55 -0400 Subject: [PATCH] Make -O and -G unary test code build under Windows Move the -O & -G code into os_notunix.go and os_unix.go. The Windows code still just panics. --- interp/os_notunix.go | 10 ++++++++++ interp/os_unix.go | 25 +++++++++++++++++++++++++ interp/test.go | 22 +--------------------- 3 files changed, 36 insertions(+), 21 deletions(-) diff --git a/interp/os_notunix.go b/interp/os_notunix.go index 66ed777a..d6aa8135 100644 --- a/interp/os_notunix.go +++ b/interp/os_notunix.go @@ -6,7 +6,10 @@ package interp import ( + "context" "fmt" + + "mvdan.cc/sh/v3/syntax" ) func mkfifo(path string, mode uint32) error { @@ -17,3 +20,10 @@ func mkfifo(path string, mode uint32) error { func hasPermissionToDir(string) bool { return true } + +// unTestOwn implements the -O and -G unary tests. Under Windows, it's unclear +// how to implement -O and -G, since Windows doesn't have the concept of a +// file owner, just ACLs, and it's unclear how to map the one to the other. +func (r *Runner) unTestOwn(ctx context.Context, op syntax.UnTestOperator, x string) bool { + panic(fmt.Sprintf("unhandled unary test op: %v", op)) +} diff --git a/interp/os_unix.go b/interp/os_unix.go index 3a82d69b..9e055cc7 100644 --- a/interp/os_unix.go +++ b/interp/os_unix.go @@ -6,7 +6,13 @@ package interp import ( + "context" + "os/user" + "strconv" + "syscall" + "golang.org/x/sys/unix" + "mvdan.cc/sh/v3/syntax" ) func mkfifo(path string, mode uint32) error { @@ -18,3 +24,22 @@ func mkfifo(path string, mode uint32) error { func hasPermissionToDir(path string) bool { return unix.Access(path, unix.X_OK) == nil } + +// unTestOwn implements the -O and -G unary tests. If the file does not exist, +// or the current user cannot be retrieved, returns false. +func (r *Runner) unTestOwn(ctx context.Context, op syntax.UnTestOperator, x string) bool { + info, err := r.stat(ctx, x) + if err != nil { + return false + } + u, err := user.Current() + if err != nil { + return false + } + if op == syntax.TsUsrOwn { + uid, _ := strconv.Atoi(u.Uid) + return uint32(uid) == info.Sys().(*syscall.Stat_t).Uid + } + gid, _ := strconv.Atoi(u.Gid) + return uint32(gid) == info.Sys().(*syscall.Stat_t).Gid +} diff --git a/interp/test.go b/interp/test.go index bd19fe12..7145ff30 100644 --- a/interp/test.go +++ b/interp/test.go @@ -8,11 +8,7 @@ import ( "fmt" "os" "os/exec" - "os/user" "regexp" - "runtime" - "strconv" - "syscall" "golang.org/x/term" @@ -205,23 +201,7 @@ func (r *Runner) unTest(ctx context.Context, op syntax.UnTestOperator, x string) case syntax.TsNot: return x == "" case syntax.TsUsrOwn, syntax.TsGrpOwn: - if runtime.GOOS == "windows" { - panic(fmt.Sprintf("unhandled unary test op: %v", op)) - } - fi, err := os.Stat(x) - if err != nil { - return false - } - u, err := user.Current() - if err != nil { - return false - } - if op == syntax.TsUsrOwn { - uid, _ := strconv.Atoi(u.Uid) - return uint32(uid) == fi.Sys().(*syscall.Stat_t).Uid - } - gid, _ := strconv.Atoi(u.Gid) - return uint32(gid) == fi.Sys().(*syscall.Stat_t).Gid + return r.unTestOwn(ctx, op, x) default: panic(fmt.Sprintf("unhandled unary test op: %v", op)) }