本文是我个人博客上的originally published。
问题
在处理我的go-pf模块时,我面临问题,以确保/dev/pf
设备可读和写作。虽然其他语言(例如Shell或Perl)提供测试功能来检查当前的用户/进程是否已在特定文件上进行读取/写入/execrissions,但在GO中,此任务并不小。
这是我们可以用perl做到的:
#!/usr/bin/env perl
my $file = "test.txt";
if(!-r $file || !-w $file) {
print $file . " is not read- and/or writable to the process\n";
exit(1);
}
print "We're all good!\n"
如果我们在外壳中运行快速的单线线,我们可以看到脚本的工作方式:
$ for i in 100 200 400 500 600 700; do echo "chmod: $i"; \
chmod $i test.txt; perl test.pl; done
chmod: 100
test.txt is not read- and/or writable to the process
chmod: 200
test.txt is not read- and/or writable to the process
chmod: 400
test.txt is not read- and/or writable to the process
chmod: 500
test.txt is not read- and/or writable to the process
chmod: 600
We're all good!
chmod: 700
We're all good!
在Go中,我们需要依靠os.Lstat,然后为我们提供Mode().Perm()
方法,我们可以用来获得文件的文件模式。但这只是租金的一半。仅仅因为文件可能返回700
的文件模式,这基本上意味着给出了读取和写入权限,因此我们可能无法由我们所有。当我们需要考虑到我们还拥有组和“其他”文件权限时,它会变得更加复杂。
解决方案
由于我找不到现成的解决方案,所以我完成了解决问题的任务 - 最好以同样简单的方式,例如在perl中。
如前所述,我们可以利用os.Lstat
作为我们的起点。使用文件权限和一些位移,我们可以轻松弄清楚是否可以为“其他”,组和用户读取/写入/执行文件。借助此信息,下一步是找出所有者和所讨论的文件组。对于类似于Unix的操作系统,GO为我们在FileInfo
上提供了os.Lstat
上的Sys()
方法,该方法由os.Lstat
返回。我们可以尝试将Sys()
的结果键入*syscall.Stat_t指针。如果成功成功,我们将获得所需的信息,即Uid
和Gid
属性。
问题第一,我们可以看到谁拥有该文件,并检查我们当前的用户是否确实是所有者。 os/user.Current方法可以帮助我们。我们的下一个任务是组所有权 - 同样,这不是一个琐碎的任务,因为用户可以参与几个组的一部分。同样,GO标准库为我们提供了User.GroupIds方法形式所需的工具,该工具将为我们提供用户参与的组的列表。使用此列表,很容易弄清楚我们的用户是否是文件组的一部分。第二个问题也解决了。对于“其他”许可,我们可以再次进行一些转移。
去填充
您可能已经猜到了,我从所有这些中构建了一些东西。 go-fileperm将我之前讨论过的所有信息都用于一个易于使用的GO模块。让我们看看
首先,我们使用New()
方法获取类型UserPerm
的实例。 New
将字符串作为参数,这是有关文件的途径。如果成功,该模块将为您提供几种检查文件访问权限(所有返回布尔值)的方法:
-
UserExecutable()
:如果当前用户/进程已在相关文件中执行权限,则返回true。 -
UserWritable()
:如果当前的用户/进程已在有问题的文件上写入权限,则返回true。 -
UserReadable()
:如果当前的用户/进程已在有关文件中读取权限,则返回true。 -
UserWriteExecutable()
:如果当前用户/进程已在此处写入和执行权限,则返回true 档案。 -
UserReadExecutable()
:如果当前用户/进程已读取和执行权限,则返回true 档案。 -
UserWriteReadExecutable()
:如果当前用户/进程已读取,写入和执行权限,则返回true 在有关文件上。
表现
由于Go-Fileperm主要利用位移动,因此模块的性能非常快。另外,我们无效分配,这总是一个加上的:)
goos: darwin
goarch: arm64
pkg: github.com/wneessen/go-fileperm
BenchmarkPermUser_UserReadable
BenchmarkPermUser_UserReadable-8 7364846 143.6 ns/op 0 B/op 0 allocs/op
BenchmarkPermUser_UserWritable
BenchmarkPermUser_UserWritable-8 7803267 154.9 ns/op 0 B/op 0 allocs/op
BenchmarkPermUser_UserExecutable
BenchmarkPermUser_UserExecutable-8 7922624 149.2 ns/op 0 B/op 0 allocs/op
BenchmarkPermUser_UserWriteReadable
BenchmarkPermUser_UserWriteReadable-8 6494815 186.1 ns/op 0 B/op 0 allocs/op
BenchmarkPermUser_UserWriteExecutable
BenchmarkPermUser_UserWriteExecutable-8 6590229 181.0 ns/op 0 B/op 0 allocs/op
BenchmarkPermUser_UserReadExecutable
BenchmarkPermUser_UserReadExecutable-8 6190532 184.7 ns/op 0 B/op 0 allocs/op
BenchmarkPermUser_UserWriteReadExecutable
BenchmarkPermUser_UserWriteReadExecutable-8 5728713 208.8 ns/op 0 B/op 0 allocs/op
PASS
完整的代码示例
让我们检查一个完整的代码示例,并应用我们在开始时使用的单线。
package main
import (
"fmt"
"log"
"github.com/wneessen/go-fileperm"
)
func main() {
p, err := fileperm.New("test.txt")
if err != nil {
log.Fatalf("failed to create UserPerm instance: %s", err)
}
fmt.Printf("test.txt is user-readable: %t\n", p.UserReadable())
fmt.Printf("test.txt is user-writable: %t\n", p.UserWritable())
fmt.Printf("test.txt is user-executable: %t\n", p.UserExecutable())
fmt.Printf("test.txt is user-read/writable: %t\n", p.UserWriteReadable())
fmt.Printf("test.txt is user-read/executable: %t\n", p.UserReadExecutable())
fmt.Printf("test.txt is user-write/executable: %t\n", p.UserWriteExecutable())
fmt.Printf("test.txt is user-read/write/executable: %t\n", p.UserWriteReadExecutable())
}
$ for i in 100 200 400 500 600 700; do echo "chmod: $i"; \
chmod $i test.txt; go run main.go; done
chmod: 100
test.txt is user-readable: false
test.txt is user-writable: false
test.txt is user-executable: true
test.txt is user-read/writable: false
test.txt is user-read/executable: false
test.txt is user-write/executable: false
test.txt is user-read/write/executable: false
chmod: 200
test.txt is user-readable: false
test.txt is user-writable: true
test.txt is user-executable: false
test.txt is user-read/writable: false
test.txt is user-read/executable: false
test.txt is user-write/executable: false
test.txt is user-read/write/executable: false
chmod: 400
test.txt is user-readable: true
test.txt is user-writable: false
test.txt is user-executable: false
test.txt is user-read/writable: false
test.txt is user-read/executable: false
test.txt is user-write/executable: false
test.txt is user-read/write/executable: false
chmod: 500
test.txt is user-readable: true
test.txt is user-writable: false
test.txt is user-executable: true
test.txt is user-read/writable: false
test.txt is user-read/executable: true
test.txt is user-write/executable: false
test.txt is user-read/write/executable: false
chmod: 600
test.txt is user-readable: true
test.txt is user-writable: true
test.txt is user-executable: false
test.txt is user-read/writable: true
test.txt is user-read/executable: false
test.txt is user-write/executable: false
test.txt is user-read/write/executable: false
chmod: 700
test.txt is user-readable: true
test.txt is user-writable: true
test.txt is user-executable: true
test.txt is user-read/writable: true
test.txt is user-read/executable: true
test.txt is user-write/executable: true
test.txt is user-read/write/executable: true
结论
您可以看到,该模块非常易于使用,希望对某些人来说是一个有用的工具。像往常一样,我已经根据MIT许可在GitHub上发布了它,因此,如果您认为有一些需要改进的事情,请随时尝试甚至做出贡献。