LoginSignup
1
1

More than 3 years have passed since last update.

go で file を touch する

Last updated at Posted at 2019-09-14

この記事について

go 言語でアプリケーションを書いていて、ファイルを touch したくなった。
でも、 os には touch がない。

どうしたものかとツイートしたら

という応答を頂いたので、書いてみた。

ソースコード

package gotouch

import (
    "runtime"
    "syscall"
    "time"
)

// Touch は、 macOS などに含まれる touch コマンドを模倣する
func Touch(path string) error {
    now := time.Now().UnixNano()
    const nano = 1000 * 1000 * 1000
    t := syscall.Timespec{Sec: now / nano, Nsec: now % nano}
    ut := []syscall.Timespec{t, t}
    err := syscall.UtimesNano(path, ut)
    if err == nil {
        return nil
    }
    isNoEnt := func(e error) bool {
        if e == syscall.ENOENT {
            return true
        }
        switch runtime.GOOS {
        case "windows":
            // Windows では syscall.ERROR_PATH_NOT_FOUND を返すことがある。
            // しかし、非 Windows 環境では syscall.ERROR_PATH_NOT_FOUND は定義されない。
            // ifdef も使えない。別ファイルにするのはめんどくさい。
            // 仕方ないので自分で定義する。
            const ERROR_PATH_NOT_FOUND = 3 // 「don't use ALL_CAPS in Go names」と言われるが、 syscall に合わせる。
            if errno, ok := e.(syscall.Errno); ok && errno == ERROR_PATH_NOT_FOUND {
                return true
            }
            return false
        case "darwin":
            return false
        case "linux":
            // たぶん OK だけど、テストしてない。
            return false
        default:
            panic("you should write something here")
        }
    }
    if !isNoEnt(err) {
        return err
    }
    fd, err := syscall.Open(path, syscall.O_CREAT|syscall.O_RDWR, 0644)
    if err != nil {
        return err
    }
    defer syscall.Close(fd)
    return nil
}

かるく説明

日本語で touch の説明をすると

  • ファイルがあれば、そのファイルのタイムスタンプを更新する
  • なければ、ファイルを作る

という感じになると思う。
しかし、上記の日本語のとおりに実装すると、《ファイルがある》と思ってから《タイムスタンプを更新する》という操作の間に誰かがファイルを削除する可能性があり、よろしくない。

そこで実際は

  • タイムスタンプの更新を試みる
  • 「ファイルがない」という理由で更新に失敗した場合、 O_TRUNC指定せずにファイルを作る

という実装になる。

O_TRUNC なしで作ることによって《「ファイルがない」という理由で更新に失敗》のあと、《ファイルを作る》という操作の前に誰かがファイルを作った場合でも不幸になることがない。

なお。
上記のソースコードは手元の macOS と Windows で動作確認した。
Linux では動かしてないけど大丈夫じゃないかと思っている。

macOS, Windows, Linux 以外だと死ぬ。

1
1
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1