如何正确实例化 os.FileMode

huangapple go评论70阅读模式
英文:

How to properly instantiate os.FileMode

问题

我看过无数个示例和教程,它们都展示了如何创建文件,而且它们都是通过设置文件的权限位来“作弊”的。我想知道如何正确实例化os.FileMode,以便在创建/更新文件时提供给写入器。

一个简单的示例如下:

func FileWrite(path string, r io.Reader, uid, gid int, perms string) (int64, error){
    w, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0664)
    if err != nil {
        if path == "" {
            w = os.Stdout
        } else {
            return 0, err
        }
    }
    defer w.Close()

    size, err := io.Copy(w, r)

    if err != nil {
        return 0, err
    }
    return size, err
}

在上面的基本函数中,权限位0664被设置了,虽然有时这样做是有道理的,但我更喜欢有一种正确设置文件权限的方法。如上所示,一个常见的例子是已知UID/GID,并且已经以整数值的形式提供,而权限位是以八进制数字的形式之前收集并插入到数据库中的字符串。

英文:

I have seen countless examples and tutorials that show how to create a file and all of them "cheat" by just setting the permission bits of the file. I would like to know / find out how to properly instantiate os.FileMode to provide to a writer during creation / updating of a file.

A crude example is this below:

func FileWrite(path string, r io.Reader, uid, gid int, perms string) (int64, error){
    w, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0664)
    if err != nil {
        if path == "" {
            w = os.Stdout
        } else {
            return 0, err
        }
    }
    defer w.Close()

    size, err := io.Copy(w, r)

    if err != nil {
        return 0, err
    }
    return size, err
}

In the basic function above permission bits 0664 is set and although this may make sense sometimes I prefer to have a proper way of setting the filemode correctly. As seen above a common example would be that the UID / GID is known and already provided as int values and the perms being octal digits that were previously gathered and inserted into a db as a string.

答案1

得分: 70

我的修复方法是定义自己的常量,因为在os或syscall中找不到任何常量:

const (
    OS_READ = 04
    OS_WRITE = 02
    OS_EX = 01
    OS_USER_SHIFT = 6
    OS_GROUP_SHIFT = 3
    OS_OTH_SHIFT = 0

    OS_USER_R = OS_READ<<OS_USER_SHIFT
    OS_USER_W = OS_WRITE<<OS_USER_SHIFT
    OS_USER_X = OS_EX<<OS_USER_SHIFT
    OS_USER_RW = OS_USER_R | OS_USER_W
    OS_USER_RWX = OS_USER_RW | OS_USER_X

    OS_GROUP_R = OS_READ<<OS_GROUP_SHIFT
    OS_GROUP_W = OS_WRITE<<OS_GROUP_SHIFT
    OS_GROUP_X = OS_EX<<OS_GROUP_SHIFT
    OS_GROUP_RW = OS_GROUP_R | OS_GROUP_W
    OS_GROUP_RWX = OS_GROUP_RW | OS_GROUP_X

    OS_OTH_R = OS_READ<<OS_OTH_SHIFT
    OS_OTH_W = OS_WRITE<<OS_OTH_SHIFT
    OS_OTH_X = OS_EX<<OS_OTH_SHIFT
    OS_OTH_RW = OS_OTH_R | OS_OTH_W
    OS_OTH_RWX = OS_OTH_RW | OS_OTH_X

    OS_ALL_R = OS_USER_R | OS_GROUP_R | OS_OTH_R
    OS_ALL_W = OS_USER_W | OS_GROUP_W | OS_OTH_W
    OS_ALL_X = OS_USER_X | OS_GROUP_X | OS_OTH_X
    OS_ALL_RW = OS_ALL_R | OS_ALL_W
    OS_ALL_RWX = OS_ALL_RW | OS_GROUP_X
)

这样我就可以直接指定我的意图:

// 创建需要放置文件的所有目录
var dir_file_mode os.FileMode
dir_file_mode = os.ModeDir | (OS_USER_RWX | OS_ALL_R)
os.MkdirAll(dir_str, dir_file_mode)

我相信这可以通过使用iota和更多的权限组合来改进,但对我来说现在已经可以工作了。

英文:

My fix has been to define my own constants as I couldn't find any in os or syscall:

    const (
        OS_READ = 04
        OS_WRITE = 02
        OS_EX = 01
        OS_USER_SHIFT = 6
        OS_GROUP_SHIFT = 3
        OS_OTH_SHIFT = 0

        OS_USER_R = OS_READ&lt;&lt;OS_USER_SHIFT
        OS_USER_W = OS_WRITE&lt;&lt;OS_USER_SHIFT
        OS_USER_X = OS_EX&lt;&lt;OS_USER_SHIFT
        OS_USER_RW = OS_USER_R | OS_USER_W
        OS_USER_RWX = OS_USER_RW | OS_USER_X

        OS_GROUP_R = OS_READ&lt;&lt;OS_GROUP_SHIFT
        OS_GROUP_W = OS_WRITE&lt;&lt;OS_GROUP_SHIFT
        OS_GROUP_X = OS_EX&lt;&lt;OS_GROUP_SHIFT
        OS_GROUP_RW = OS_GROUP_R | OS_GROUP_W
        OS_GROUP_RWX = OS_GROUP_RW | OS_GROUP_X

        OS_OTH_R = OS_READ&lt;&lt;OS_OTH_SHIFT
        OS_OTH_W = OS_WRITE&lt;&lt;OS_OTH_SHIFT
        OS_OTH_X = OS_EX&lt;&lt;OS_OTH_SHIFT
        OS_OTH_RW = OS_OTH_R | OS_OTH_W
        OS_OTH_RWX = OS_OTH_RW | OS_OTH_X

        OS_ALL_R = OS_USER_R | OS_GROUP_R | OS_OTH_R
        OS_ALL_W = OS_USER_W | OS_GROUP_W | OS_OTH_W
        OS_ALL_X = OS_USER_X | OS_GROUP_X | OS_OTH_X
        OS_ALL_RW = OS_ALL_R | OS_ALL_W
        OS_ALL_RWX = OS_ALL_RW | OS_GROUP_X
)

This then allows me to specify my intent directly:

        // Create any directories needed to put this file in them
        var dir_file_mode os.FileMode
        dir_file_mode = os.ModeDir | (OS_USER_RWX | OS_ALL_R)
        os.MkdirAll(dir_str, dir_file_mode)

I'm sure this could be improved by use of iota, and some more combinations of permissions, but it works for me for now.

答案2

得分: 46

FileMode只是一个uint32类型的变量。http://golang.org/pkg/os/#FileMode

通过使用常量来设置它并不是“作弊”,你可以像其他数值一样使用它。如果你不使用常量,你可以对有效的数值进行转换:

mode := int(0777)
os.FileMode(mode)
英文:

FileMode is just a uint32. http://golang.org/pkg/os/#FileMode

Setting via constants isn't "cheating", you use it like other numeric values. If you're not using a constant, you can use a conversion on valid numeric values:

mode := int(0777)
os.FileMode(mode)

答案3

得分: 0

添加到Chris Hopkins的答案中

你可以通过执行fs.fileMode(dir_file_mode)将值转换为fs.fileMode类型

此外,常量定义中有一个拼写错误:

OS_ALL_RWX = OS_ALL_RW | OS_GROUP_X(错误)

OS_ALL_RWX = OS_ALL_RW | OS_ALL_X(正确)
英文:

Adding to Chris Hopkins answer

You can convert the value to type fs.fileMode by doing fs.fileMode(dir_file_mode)

Also, there is one typo in the constants defined:

OS_ALL_RWX = OS_ALL_RW | OS_GROUP_X (Incorrect)

OS_ALL_RWX = OS_ALL_RW | OS_ALL_X (Correct)

答案4

得分: 0

此外,除了Chris Hopkins的回答之外,您还可以使用与POSIX C API中使用的相同命名约定的方式来组合任何文件权限所需的值,这些值可以在syscall包中找到。

因此,您可以使用以下代码而不是通过计算来定义自己的常量(正如Chris的回答中所示):

OS_USER_R = OS_READ<<OS_USER_SHIFT

您可以改为使用以下代码:

// 用户读取、写入、执行位
syscall.S_IRUSR
syscall.S_IWUSR
syscall.S_IXUSR
// 组读取、写入、执行位
syscall.S_IRGRP
syscall.S_IWGRP
syscall.S_IXGRP
// 其他用户读取、写入、执行位
syscall.S_IROTH
syscall.S_IWOTH
syscall.S_IXOTH

然后,您可以根据需要组合其他权限,或者使用一些与POSIX C API匹配的预定义常量,或者使用S_IREAD,S_IWRITE,S_IEXEC等简写形式。

英文:

Also adding to Chris Hopkins answer, the values you need to compose any of the file permissions using the same naming convention as used in the POSIX C API are found in the syscall package.

So instead of defining your own constants by computing them (which is still trivial as seen in Chris's answer)

OS_USER_R = OS_READ&lt;&lt;OS_USER_SHIFT

You can instead just use

// user read, write, execute bit
syscall.S_IRUSR
syscall.S_IWUSR
syscall.S_IXUSR
// group read, write, execute bit
syscall.S_IRGRP
syscall.S_IWGRP
syscall.S_IXGRP
// world/other read, write, execute bit
syscall.S_IROTH
syscall.S_IWOTH
syscall.S_IXOTH

And you can then compose any others as needed, or use some of the additional pre-defined ones matching the POSIX C API, or shorthands like S_IREAD, S_IWRITE, S_IEXEC, etc.

huangapple
  • 本文由 发表于 2015年3月11日 00:47:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/28969455.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定