如何在Go语言中检查文件是否可执行?

14

我该如何在Go语言中编写一个函数来检查文件是否可执行?给定一个os.FileInfo,我可以获取os.FileInfo.Mode(),但我会在尝试解析权限位时陷入困境。

测试用例:

#!/usr/bin/env bash
function setup() {
  mkdir -p test/foo/bar
  touch test/foo/bar/{baz.txt,quux.sh}
  chmod +x test/foo/bar/quux.sh
}

function teardown() { rm -r ./test }

setup
import (
    "os"
    "path/filepath"
    "fmt"
)

func IsExectuable(mode os.FileMode) bool {
    // ???
}

func main() {
    filepath.Walk("test", func(path string, info os.FileInfo, err error) error {
        if err != nil || info.IsDir() {
            return err
        }
        fmt.Printf("%v %v", path, IsExectuable(info.Mode().Perm()))
    }
}
// should print "test/foo/bar/baz.txt false"
//              "test/foo/bar/quux.txt true"

我只关心Unix文件,如果解决方案也适用于Windows系统,则加分。


2
可执行权限是由谁拥有?所有者?组?其他人? - icza
我曾经想知道当前用户是否可以执行某个文件,但是你的更一般化的回答非常完美。 - Steven Kalt
2个回答

16
文件是否可执行存储在Unix权限位中(通过FileMode.Perm()返回,它基本上是最低的9位(0777八进制掩码)。请注意,由于我们在下面的解决方案中使用了位掩码,因此调用Perm()是不必要的。

它们的含义是:

rwxrwxrwx

前三位是所有者的权限,接下来三位是组的权限,最后三位是其他人的权限。

要判断文件是否可被所有者执行,请使用掩码0100

func IsExecOwner(mode os.FileMode) bool {
    return mode&0100 != 0
}

同样地,要判断可执行文件是否可被组使用,请使用比特掩码0010

func IsExecGroup(mode os.FileMode) bool {
    return mode&0010 != 0
}

而其他人则使用位掩码0001

func IsExecOther(mode os.FileMode) bool {
    return mode&0001 != 0
}

要确定文件是否可由上述任何一种执行,请使用位掩码0111

func IsExecAny(mode os.FileMode) bool {
    return mode&0111 != 0
}

要判断文件是否可由上述所有人执行,请再次使用位掩码0111,但请检查结果是否等于0111

func IsExecAll(mode os.FileMode) bool {
    return mode&0111 == 0111
}

2
检查当前用户(基于真实UID和GID)是否可以执行文件的POSIX系统调用是access,并且需要使用X_OK。在支持ACL的平台上(如Linux),这还应考虑文件的ACL。 - Eryk Sun
如果文件所有者是当前用户,则使用 IsExecOwner()。否则,如果当前用户在文件所属组中,则使用 IsExecGroup(),否则使用 IsExecOther() - icza
但是如何测试呢?如果用户在组内呢? - Gabriel
只需要使用 mode := X_OK 吗?参考链接:https://godoc.org/golang.org/x/sys/unix#Access - Gabriel
1
如何在Windows上使用Go实现这个功能? - Gabriel
显示剩余2条评论

1
其他评论是正确的,文件的权限位不足以确定当前用户是否可以执行该文件,特别是没有文件所有权的情况下。实际上,当前用户是否可以执行对系统来说是无意义的,因为系统关心的是当前进程是否可以执行文件,而不管当前用户通常是否可以执行(例如在他们的shell提示符下进行setuid/setgid操作)。
我不是Go程序员,但我已经添加了一个函数here,我相信它可以执行这个技巧并使用已经提到的内容。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接