2023-03-31 21:16:02 +01:00
|
|
|
// Copyright (c) Tailscale Inc & AUTHORS
|
|
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
|
|
|
|
//go:build !js && !windows
|
|
|
|
|
|
|
|
package atomicfile
|
|
|
|
|
|
|
|
import (
|
|
|
|
"net"
|
2023-04-04 16:40:53 +01:00
|
|
|
"os"
|
2023-03-31 21:16:02 +01:00
|
|
|
"path/filepath"
|
2023-04-04 16:40:53 +01:00
|
|
|
"runtime"
|
2023-03-31 21:16:02 +01:00
|
|
|
"strings"
|
|
|
|
"testing"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestDoesNotOverwriteIrregularFiles(t *testing.T) {
|
|
|
|
// Per tailscale/tailscale#7658 as one example, almost any imagined use of
|
|
|
|
// atomicfile.Write should likely not attempt to overwrite an irregular file
|
|
|
|
// such as a device node, socket, or named pipe.
|
|
|
|
|
2023-04-04 16:40:53 +01:00
|
|
|
const filename = "TestDoesNotOverwriteIrregularFiles"
|
|
|
|
var path string
|
|
|
|
// macOS private temp does not allow unix socket creation, but /tmp does.
|
|
|
|
if runtime.GOOS == "darwin" {
|
|
|
|
path = filepath.Join("/tmp", filename)
|
|
|
|
t.Cleanup(func() { os.Remove(path) })
|
|
|
|
} else {
|
|
|
|
path = filepath.Join(t.TempDir(), filename)
|
|
|
|
}
|
2023-03-31 21:16:02 +01:00
|
|
|
|
|
|
|
// The least troublesome thing to make that is not a file is a unix socket.
|
2023-04-17 23:38:24 +01:00
|
|
|
// Making a null device sadly requires root.
|
2023-04-04 16:40:53 +01:00
|
|
|
l, err := net.ListenUnix("unix", &net.UnixAddr{Name: path, Net: "unix"})
|
2023-03-31 21:16:02 +01:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
defer l.Close()
|
|
|
|
|
2023-04-04 16:40:53 +01:00
|
|
|
err = WriteFile(path, []byte("hello"), 0644)
|
2023-03-31 21:16:02 +01:00
|
|
|
if err == nil {
|
|
|
|
t.Fatal("expected error, got nil")
|
|
|
|
}
|
|
|
|
if !strings.Contains(err.Error(), "is not a regular file") {
|
|
|
|
t.Fatalf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
}
|