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
8package unix
9
10import (
11	"unsafe"
12)
13
14// This file simulates fstatfs on z/OS using fstatvfs and w_getmntent.
15
16func Fstatfs(fd int, stat *Statfs_t) (err error) {
17	var stat_v Statvfs_t
18	err = Fstatvfs(fd, &stat_v)
19	if err == nil {
20		// populate stat
21		stat.Type = 0
22		stat.Bsize = stat_v.Bsize
23		stat.Blocks = stat_v.Blocks
24		stat.Bfree = stat_v.Bfree
25		stat.Bavail = stat_v.Bavail
26		stat.Files = stat_v.Files
27		stat.Ffree = stat_v.Ffree
28		stat.Fsid = stat_v.Fsid
29		stat.Namelen = stat_v.Namemax
30		stat.Frsize = stat_v.Frsize
31		stat.Flags = stat_v.Flag
32		for passn := 0; passn < 5; passn++ {
33			switch passn {
34			case 0:
35				err = tryGetmntent64(stat)
36				break
37			case 1:
38				err = tryGetmntent128(stat)
39				break
40			case 2:
41				err = tryGetmntent256(stat)
42				break
43			case 3:
44				err = tryGetmntent512(stat)
45				break
46			case 4:
47				err = tryGetmntent1024(stat)
48				break
49			default:
50				break
51			}
52			//proceed to return if: err is nil (found), err is nonnil but not ERANGE (another error occurred)
53			if err == nil || err != nil && err != ERANGE {
54				break
55			}
56		}
57	}
58	return err
59}
60
61func tryGetmntent64(stat *Statfs_t) (err error) {
62	var mnt_ent_buffer struct {
63		header       W_Mnth
64		filesys_info [64]W_Mntent
65	}
66	var buffer_size int = int(unsafe.Sizeof(mnt_ent_buffer))
67	fs_count, err := W_Getmntent((*byte)(unsafe.Pointer(&mnt_ent_buffer)), buffer_size)
68	if err != nil {
69		return err
70	}
71	err = ERANGE //return ERANGE if no match is found in this batch
72	for i := 0; i < fs_count; i++ {
73		if stat.Fsid == uint64(mnt_ent_buffer.filesys_info[i].Dev) {
74			stat.Type = uint32(mnt_ent_buffer.filesys_info[i].Fstname[0])
75			err = nil
76			break
77		}
78	}
79	return err
80}
81
82func tryGetmntent128(stat *Statfs_t) (err error) {
83	var mnt_ent_buffer struct {
84		header       W_Mnth
85		filesys_info [128]W_Mntent
86	}
87	var buffer_size int = int(unsafe.Sizeof(mnt_ent_buffer))
88	fs_count, err := W_Getmntent((*byte)(unsafe.Pointer(&mnt_ent_buffer)), buffer_size)
89	if err != nil {
90		return err
91	}
92	err = ERANGE //return ERANGE if no match is found in this batch
93	for i := 0; i < fs_count; i++ {
94		if stat.Fsid == uint64(mnt_ent_buffer.filesys_info[i].Dev) {
95			stat.Type = uint32(mnt_ent_buffer.filesys_info[i].Fstname[0])
96			err = nil
97			break
98		}
99	}
100	return err
101}
102
103func tryGetmntent256(stat *Statfs_t) (err error) {
104	var mnt_ent_buffer struct {
105		header       W_Mnth
106		filesys_info [256]W_Mntent
107	}
108	var buffer_size int = int(unsafe.Sizeof(mnt_ent_buffer))
109	fs_count, err := W_Getmntent((*byte)(unsafe.Pointer(&mnt_ent_buffer)), buffer_size)
110	if err != nil {
111		return err
112	}
113	err = ERANGE //return ERANGE if no match is found in this batch
114	for i := 0; i < fs_count; i++ {
115		if stat.Fsid == uint64(mnt_ent_buffer.filesys_info[i].Dev) {
116			stat.Type = uint32(mnt_ent_buffer.filesys_info[i].Fstname[0])
117			err = nil
118			break
119		}
120	}
121	return err
122}
123
124func tryGetmntent512(stat *Statfs_t) (err error) {
125	var mnt_ent_buffer struct {
126		header       W_Mnth
127		filesys_info [512]W_Mntent
128	}
129	var buffer_size int = int(unsafe.Sizeof(mnt_ent_buffer))
130	fs_count, err := W_Getmntent((*byte)(unsafe.Pointer(&mnt_ent_buffer)), buffer_size)
131	if err != nil {
132		return err
133	}
134	err = ERANGE //return ERANGE if no match is found in this batch
135	for i := 0; i < fs_count; i++ {
136		if stat.Fsid == uint64(mnt_ent_buffer.filesys_info[i].Dev) {
137			stat.Type = uint32(mnt_ent_buffer.filesys_info[i].Fstname[0])
138			err = nil
139			break
140		}
141	}
142	return err
143}
144
145func tryGetmntent1024(stat *Statfs_t) (err error) {
146	var mnt_ent_buffer struct {
147		header       W_Mnth
148		filesys_info [1024]W_Mntent
149	}
150	var buffer_size int = int(unsafe.Sizeof(mnt_ent_buffer))
151	fs_count, err := W_Getmntent((*byte)(unsafe.Pointer(&mnt_ent_buffer)), buffer_size)
152	if err != nil {
153		return err
154	}
155	err = ERANGE //return ERANGE if no match is found in this batch
156	for i := 0; i < fs_count; i++ {
157		if stat.Fsid == uint64(mnt_ent_buffer.filesys_info[i].Dev) {
158			stat.Type = uint32(mnt_ent_buffer.filesys_info[i].Fstname[0])
159			err = nil
160			break
161		}
162	}
163	return err
164}
165