1// Copyright 2020 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5//go:build zos && s390x
6// +build zos,s390x
7
8// This test is based on mmap_unix_test, but tweaked for z/OS, which does not support memadvise
9// or anonymous mmapping.
10
11package unix_test
12
13import (
14	"fmt"
15	"io/ioutil"
16	"os"
17	"path/filepath"
18	"testing"
19
20	"golang.org/x/sys/unix"
21)
22
23func TestMmap(t *testing.T) {
24	tmpdir := mktmpdir(t)
25	filename := filepath.Join(filepath.Join(tmpdir, "testdata"), "memmapped_file")
26	destination, err := os.Create(filename)
27	if err != nil {
28		t.Fatal("os.Create:", err)
29		return
30	}
31	defer os.RemoveAll(tmpdir)
32
33	fmt.Fprintf(destination, "%s\n", "0 <- Flipped between 0 and 1 when test runs successfully")
34	fmt.Fprintf(destination, "%s\n", "//Do not change contents - mmap test relies on this")
35	destination.Close()
36	fd, err := unix.Open(filename, unix.O_RDWR, 0777)
37	if err != nil {
38		t.Fatalf("Open: %v", err)
39	}
40
41	b, err := unix.Mmap(fd, 0, 8, unix.PROT_READ, unix.MAP_SHARED)
42	if err != nil {
43		t.Fatalf("Mmap: %v", err)
44	}
45
46	if err := unix.Mprotect(b, unix.PROT_READ|unix.PROT_WRITE); err != nil {
47		t.Fatalf("Mprotect: %v", err)
48	}
49
50	// Flip flag in test file via mapped memory
51	flagWasZero := true
52	if b[0] == '0' {
53		b[0] = '1'
54	} else if b[0] == '1' {
55		b[0] = '0'
56		flagWasZero = false
57	}
58
59	if err := unix.Msync(b, unix.MS_SYNC); err != nil {
60		t.Fatalf("Msync: %v", err)
61	}
62
63	// Read file from FS to ensure flag flipped after msync
64	buf, err := ioutil.ReadFile(filename)
65	if err != nil {
66		t.Fatalf("Could not read mmapped file from disc for test: %v", err)
67	}
68	if flagWasZero && buf[0] != '1' || !flagWasZero && buf[0] != '0' {
69		t.Error("Flag flip in MAP_SHARED mmapped file not visible")
70	}
71
72	if err := unix.Munmap(b); err != nil {
73		t.Fatalf("Munmap: %v", err)
74	}
75}
76
77func mktmpdir(t *testing.T) string {
78	tmpdir, err := ioutil.TempDir("", "memmapped_file")
79	if err != nil {
80		t.Fatal("mktmpdir:", err)
81	}
82	if err := os.Mkdir(filepath.Join(tmpdir, "testdata"), 0700); err != nil {
83		os.RemoveAll(tmpdir)
84		t.Fatal("mktmpdir:", err)
85	}
86	return tmpdir
87}
88