ファイルを一括で記述したかったので、ioutil.WriteFile
を使おうと思いました。この第三引数の部分がいまいち理解できていないので調べていました。
定義
func WriteFile(filename string, data []byte, perm os.FileMode) error
よくここにos.ModePrem
とか書くけどあれなによ?というやつです。FileMode
の定義も読んでみます。様々なデバイスファイルやモードが定義されています。単にファイルを書きたいときだと、os.ModePrem
でオッケーで、Unix の0777のパーミッションがファイルに設定されるように見えます。
const (
// The single letters are the abbreviations
// used by the String method's formatting.
ModeDir FileMode = 1 << (32 - 1 - iota) // d: is a directory
ModeAppend // a: append-only
ModeExclusive // l: exclusive use
ModeTemporary // T: temporary file; Plan 9 only
ModeSymlink // L: symbolic link
ModeDevice // D: device file
ModeNamedPipe // p: named pipe (FIFO)
ModeSocket // S: Unix domain socket
ModeSetuid // u: setuid
ModeSetgid // g: setgid
ModeCharDevice // c: Unix character device, when ModeDevice is set
ModeSticky // t: sticky
ModeIrregular // ?: non-regular file; nothing else is known about this file
// Mask for the type bits. For regular files, none will be set.
ModeType = ModeDir | ModeSymlink | ModeNamedPipe | ModeSocket | ModeDevice | ModeCharDevice | ModeIrregular
ModePerm FileMode = 0777 // Unix permission bits
)
ファイルのパーミッションがうまく動作しない理由
それなら、普通に書きこむファイルのパーミッションを設定できるのでは?と思いしらべてみると、次のように書けます。
package main
import (
"fmt"
"io/ioutil"
"os"
"strconv"
)
func main() {
ioutil.WriteFile("ModePerm.txt", []byte("ModePerm.txt"), os.ModePerm)
fmt.Println(os.ModePerm.IsRegular())
perm := "0777"
perm32, _ := strconv.ParseUint(perm, 8, 32)
ioutil.WriteFile("777.txt", []byte("some"), os.FileMode(perm32))
fmt.Println(perm32)
perm = "0644"
perm32, _ = strconv.ParseUint(perm, 8, 32)
ioutil.WriteFile("644.txt", []byte("some"), os.FileMode(perm32))
fmt.Println(perm32)
perm = "0666"
perm32, _ = strconv.ParseUint(perm, 8, 32)
ioutil.WriteFile("666.txt", []byte("some"), os.FileMode(perm32))
// os.Chmod("./666.txt", os.FileMode(perm32))
}
これを実行すると、4つのファイルが生成されて、想定通りのパーミッションが設定されるといいのですが、そうなりません。
ls -l
total 4
-rw-r--r-- 1 ushio ushio 4 Dec 21 08:45 644.txt
-rw-r--r-- 1 ushio ushio 4 Dec 21 08:45 666.txt
-rwxr-xr-x 1 ushio ushio 4 Dec 21 08:45 777.txt
-rwxr-xr-x 1 ushio ushio 12 Dec 21 08:45 ModePerm.txt
-rw-r--r-- 1 ushio ushio 47 Dec 21 08:11 go.mod
-rw-r--r-- 1 ushio ushio 809 Dec 21 08:44 main.go
なんでやねん!と思って私のGo師匠であるかえる師匠に聞いてみたのですが、こんなStackOverflowの記事を見つけてくれました。
これを読むと、これは、go の問題ではなく、OS で設定されている umask
の問題では?との答えがありました。
umask
umask() sets the calling process's file mode creation mask (umask) to mask & 0777 (i.e., only the file
permission bits of mask are used),and returns the previous value of the mask.The umask is used by open(2), mkdir(2), and other system calls that create files to modify the permissions placed on newly created files or directories. Specifically, permissions in the umask are turned off from the mode argument to open(2) and mkdir(2).
Umaskは、openやmkdirのシステムコールで使われて、新しいファイルやディレクトリを作るときにパーミッションをモディファイするとあります。ここで、私が今使っているWSLのumaskを見てみましょう。
$ umask
022
022 ですね、これをマスクするということは、Unixのファイルパーミッション設定は、4(read) 2(write) 1(execute) なので、022は所有者以外の書き込み権限なので、それでマスクをすると、書き込み権限がなくなることになります。
実際の上の実行例を見てみると、644は正しく設定されているのに、666は、644に変更されています。ModePerm も元が777なのが、755に変更されています。
想定どおりのパーミッションを設定したい場合は?
では、想定通りのパーミッションを設定するにはどういう方法がよいでしょう?先ほどのStack Overflow からたどれるWikiで次のような記述があります。
In Unix-like systems, each file has a set of attributes that control who can read, write or execute it. When a program creates a file the file permissions are restricted by the mask. If the mask has a bit set to "1", then the corresponding initial file permission will be disabled. A bit set to "0" in the mask means that the corresponding permission will be determined by the program and the file system. In other words, the mask acts as a last-stage filter that strips away permissions as a file is created; each bit that is set to a "1" strips away its corresponding permission. Permissions may be changed later by users and programs using chmod.
Unixシステムでは、ファイルを作成した時にはマスクで、制限されてるとあります。パーミッションはchmodを使って後で変えられるかもしれないとあります。つまり、想定通りのパーミッション例えば、0666
を設定したい場合は、
os.Chmod("./666.txt", os.FileMode(perm32))
を追記すればいいことになります。そうすれば、666に無事設定されていることがわかると思います。
ls -l
total 4
-rw-r--r-- 1 ushio ushio 4 Dec 21 08:49 644.txt
-rw-rw-rw- 1 ushio ushio 4 Dec 21 08:49 666.txt
-rwxr-xr-x 1 ushio ushio 4 Dec 21 08:49 777.txt
-rwxr-xr-x 1 ushio ushio 12 Dec 21 08:49 ModePerm.txt
-rw-r--r-- 1 ushio ushio 47 Dec 21 08:11 go.mod
-rw-r--r-- 1 ushio ushio 651 Dec 21 08:49 main.go