rename all remaining packages to internal/ (#12418)

This is to ensure that there are no projects
that try to import `minio/minio/pkg` into
their own repo. Any such common packages should
go to `https://github.com/minio/pkg`
This commit is contained in:
Harshavardhana
2021-06-01 14:59:40 -07:00
committed by GitHub
parent bf87c4b1e4
commit 1f262daf6f
540 changed files with 757 additions and 778 deletions

View File

@@ -0,0 +1,37 @@
// +build linux
// Copyright (c) 2015-2021 MinIO, Inc.
//
// This file is part of MinIO Object Storage stack
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package mountinfo
// mountInfo - This represents a single line in /proc/mounts.
type mountInfo struct {
Device string
Path string
FSType string
Options []string
Freq string
Pass string
}
func (m mountInfo) String() string {
return m.Path
}
// mountInfos - This represents the entire /proc/mounts.
type mountInfos []mountInfo

View File

@@ -0,0 +1,162 @@
// +build linux
// Copyright (c) 2015-2021 MinIO, Inc.
//
// This file is part of MinIO Object Storage stack
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package mountinfo
import (
"bufio"
"fmt"
"io"
"os"
"path/filepath"
"strconv"
"strings"
"syscall"
)
const (
// Number of fields per line in /proc/mounts as per the fstab man page.
expectedNumFieldsPerLine = 6
// Location of the mount file to use
procMountsPath = "/proc/mounts"
)
// IsLikelyMountPoint determines if a directory is a mountpoint.
func IsLikelyMountPoint(path string) bool {
s1, err := os.Lstat(path)
if err != nil {
return false
}
// A symlink can never be a mount point
if s1.Mode()&os.ModeSymlink != 0 {
return false
}
s2, err := os.Lstat(filepath.Dir(strings.TrimSuffix(path, "/")))
if err != nil {
return false
}
// If the directory has a different device as parent, then it is a mountpoint.
if s1.Sys().(*syscall.Stat_t).Dev != s2.Sys().(*syscall.Stat_t).Dev {
// path/.. on a different device as path
return true
}
// path/.. is the same i-node as path - this check is for bind mounts.
return s1.Sys().(*syscall.Stat_t).Ino == s2.Sys().(*syscall.Stat_t).Ino
}
// CheckCrossDevice - check if any list of paths has any sub-mounts at /proc/mounts.
func CheckCrossDevice(absPaths []string) error {
return checkCrossDevice(absPaths, procMountsPath)
}
// Check cross device is an internal function.
func checkCrossDevice(absPaths []string, mountsPath string) error {
mounts, err := readProcMounts(mountsPath)
if err != nil {
return err
}
for _, path := range absPaths {
if err := mounts.checkCrossMounts(path); err != nil {
return err
}
}
return nil
}
// CheckCrossDevice - check if given path has any sub-mounts in the input mounts list.
func (mts mountInfos) checkCrossMounts(path string) error {
if !filepath.IsAbs(path) {
return fmt.Errorf("Invalid argument, path (%s) is expected to be absolute", path)
}
var crossMounts mountInfos
for _, mount := range mts {
// Add a separator to indicate that this is a proper mount-point.
// This is to avoid a situation where prefix is '/tmp/fsmount'
// and mount path is /tmp/fs. In such a scenario we need to check for
// `/tmp/fs/` to be a common prefix amount other mounts.
mpath := strings.TrimSuffix(mount.Path, "/") + "/"
ppath := strings.TrimSuffix(path, "/") + "/"
if strings.HasPrefix(mpath, ppath) {
// At this point if the mount point has a common prefix two conditions can happen.
// - mount.Path matches exact with `path` means we can proceed no error here.
// - mount.Path doesn't match (means cross-device mount), should error out.
if mount.Path != path {
crossMounts = append(crossMounts, mount)
}
}
}
msg := `Cross-device mounts detected on path (%s) at following locations %s. Export path should not have any sub-mounts, refusing to start.`
if len(crossMounts) > 0 {
// if paths didn't match then we do have cross-device mount.
return fmt.Errorf(msg, path, crossMounts)
}
return nil
}
// readProcMounts reads the given mountFilePath (normally /proc/mounts) and produces a hash
// of the contents. If the out argument is not nil, this fills it with MountPoint structs.
func readProcMounts(mountFilePath string) (mountInfos, error) {
file, err := os.Open(mountFilePath)
if err != nil {
return nil, err
}
defer file.Close()
return parseMountFrom(file)
}
func parseMountFrom(file io.Reader) (mountInfos, error) {
var mounts = mountInfos{}
scanner := bufio.NewReader(file)
for {
line, err := scanner.ReadString('\n')
if err == io.EOF {
break
}
fields := strings.Fields(line)
if len(fields) != expectedNumFieldsPerLine {
// ignore incorrect lines.
continue
}
// Freq should be an integer.
if _, err := strconv.Atoi(fields[4]); err != nil {
return nil, err
}
// Pass should be an integer.
if _, err := strconv.Atoi(fields[5]); err != nil {
return nil, err
}
mounts = append(mounts, mountInfo{
Device: fields[0],
Path: fields[1],
FSType: fields[2],
Options: strings.Split(fields[3], ","),
Freq: fields[4],
Pass: fields[5],
})
}
return mounts, nil
}

View File

@@ -0,0 +1,251 @@
// +build linux
// Copyright (c) 2015-2021 MinIO, Inc.
//
// This file is part of MinIO Object Storage stack
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package mountinfo
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
"testing"
)
// Tests cross device mount verification function, for both failure
// and success cases.
func TestCrossDeviceMountPaths(t *testing.T) {
successCase :=
`/dev/0 /path/to/0/1 type0 flags 0 0
/dev/1 /path/to/1 type1 flags 1 1
/dev/2 /path/to/1/2 type2 flags,1,2=3 2 2
/dev/3 /path/to/1.1 type3 falgs,1,2=3 3 3
`
dir, err := ioutil.TempDir("", "TestReadProcmountInfos")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dir)
mountsPath := filepath.Join(dir, "mounts")
if err = ioutil.WriteFile(mountsPath, []byte(successCase), 0666); err != nil {
t.Fatal(err)
}
// Failure case where we detected successfully cross device mounts.
{
var absPaths = []string{"/path/to/1"}
if err = checkCrossDevice(absPaths, mountsPath); err == nil {
t.Fatal("Expected to fail, but found success")
}
mp := []mountInfo{
{"/dev/2", "/path/to/1/2", "type2", []string{"flags"}, "2", "2"},
}
msg := fmt.Sprintf("Cross-device mounts detected on path (/path/to/1) at following locations %s. Export path should not have any sub-mounts, refusing to start.", mp)
if err.Error() != msg {
t.Fatalf("Expected msg %s, got %s", msg, err)
}
}
// Failure case when input path is not absolute.
{
var absPaths = []string{"."}
if err = checkCrossDevice(absPaths, mountsPath); err == nil {
t.Fatal("Expected to fail for non absolute paths")
}
expectedErrMsg := fmt.Sprintf("Invalid argument, path (%s) is expected to be absolute", ".")
if err.Error() != expectedErrMsg {
t.Fatalf("Expected %s, got %s", expectedErrMsg, err)
}
}
// Success case, where path doesn't have any mounts.
{
var absPaths = []string{"/path/to/x"}
if err = checkCrossDevice(absPaths, mountsPath); err != nil {
t.Fatalf("Expected success, failed instead (%s)", err)
}
}
}
// Tests cross device mount verification function, for both failure
// and success cases.
func TestCrossDeviceMount(t *testing.T) {
successCase :=
`/dev/0 /path/to/0/1 type0 flags 0 0
/dev/1 /path/to/1 type1 flags 1 1
/dev/2 /path/to/1/2 type2 flags,1,2=3 2 2
/dev/3 /path/to/1.1 type3 falgs,1,2=3 3 3
`
dir, err := ioutil.TempDir("", "TestReadProcmountInfos")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dir)
mountsPath := filepath.Join(dir, "mounts")
if err = ioutil.WriteFile(mountsPath, []byte(successCase), 0666); err != nil {
t.Fatal(err)
}
mounts, err := readProcMounts(mountsPath)
if err != nil {
t.Fatal(err)
}
// Failure case where we detected successfully cross device mounts.
{
if err = mounts.checkCrossMounts("/path/to/1"); err == nil {
t.Fatal("Expected to fail, but found success")
}
mp := []mountInfo{
{"/dev/2", "/path/to/1/2", "type2", []string{"flags"}, "2", "2"},
}
msg := fmt.Sprintf("Cross-device mounts detected on path (/path/to/1) at following locations %s. Export path should not have any sub-mounts, refusing to start.", mp)
if err.Error() != msg {
t.Fatalf("Expected msg %s, got %s", msg, err)
}
}
// Failure case when input path is not absolute.
{
if err = mounts.checkCrossMounts("."); err == nil {
t.Fatal("Expected to fail for non absolute paths")
}
expectedErrMsg := fmt.Sprintf("Invalid argument, path (%s) is expected to be absolute", ".")
if err.Error() != expectedErrMsg {
t.Fatalf("Expected %s, got %s", expectedErrMsg, err)
}
}
// Success case, where path doesn't have any mounts.
{
if err = mounts.checkCrossMounts("/path/to/x"); err != nil {
t.Fatalf("Expected success, failed instead (%s)", err)
}
}
}
// Tests read proc mounts file.
func TestReadProcmountInfos(t *testing.T) {
successCase :=
`/dev/0 /path/to/0 type0 flags 0 0
/dev/1 /path/to/1 type1 flags 1 1
/dev/2 /path/to/2 type2 flags,1,2=3 2 2
`
dir, err := ioutil.TempDir("", "TestReadProcmountInfos")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dir)
mountsPath := filepath.Join(dir, "mounts")
if err = ioutil.WriteFile(mountsPath, []byte(successCase), 0666); err != nil {
t.Fatal(err)
}
// Verifies if reading each line worked properly.
{
var mounts mountInfos
mounts, err = readProcMounts(mountsPath)
if err != nil {
t.Fatal(err)
}
if len(mounts) != 3 {
t.Fatalf("expected 3 mounts, got %d", len(mounts))
}
mp := mountInfo{"/dev/0", "/path/to/0", "type0", []string{"flags"}, "0", "0"}
if !mountPointsEqual(mounts[0], mp) {
t.Errorf("got unexpected MountPoint[0]: %#v", mounts[0])
}
mp = mountInfo{"/dev/1", "/path/to/1", "type1", []string{"flags"}, "1", "1"}
if !mountPointsEqual(mounts[1], mp) {
t.Errorf("got unexpected mountInfo[1]: %#v", mounts[1])
}
mp = mountInfo{"/dev/2", "/path/to/2", "type2", []string{"flags", "1", "2=3"}, "2", "2"}
if !mountPointsEqual(mounts[2], mp) {
t.Errorf("got unexpected mountInfo[2]: %#v", mounts[2])
}
}
// Failure case mounts path doesn't exist, if not fail.
{
if _, err = readProcMounts(filepath.Join(dir, "non-existent")); err != nil && !os.IsNotExist(err) {
t.Fatal(err)
}
}
}
// Tests read proc mounts reader.
func TestReadProcMountFrom(t *testing.T) {
successCase :=
`/dev/0 /path/to/0 type0 flags 0 0
/dev/1 /path/to/1 type1 flags 1 1
/dev/2 /path/to/2 type2 flags,1,2=3 2 2
`
// Success case, verifies if parsing works properly.
{
mounts, err := parseMountFrom(strings.NewReader(successCase))
if err != nil {
t.Errorf("expected success")
}
if len(mounts) != 3 {
t.Fatalf("expected 3 mounts, got %d", len(mounts))
}
mp := mountInfo{"/dev/0", "/path/to/0", "type0", []string{"flags"}, "0", "0"}
if !mountPointsEqual(mounts[0], mp) {
t.Errorf("got unexpected mountInfo[0]: %#v", mounts[0])
}
mp = mountInfo{"/dev/1", "/path/to/1", "type1", []string{"flags"}, "1", "1"}
if !mountPointsEqual(mounts[1], mp) {
t.Errorf("got unexpected mountInfo[1]: %#v", mounts[1])
}
mp = mountInfo{"/dev/2", "/path/to/2", "type2", []string{"flags", "1", "2=3"}, "2", "2"}
if !mountPointsEqual(mounts[2], mp) {
t.Errorf("got unexpected mountInfo[2]: %#v", mounts[2])
}
}
// Error cases where parsing fails with invalid Freq and Pass params.
{
errorCases := []string{
"/dev/1 /path/to/mount type flags a 0\n",
"/dev/2 /path/to/mount type flags 0 b\n",
}
for _, ec := range errorCases {
_, rerr := parseMountFrom(strings.NewReader(ec))
if rerr == nil {
t.Errorf("expected error")
}
}
}
}
// Helpers for tests.
// Check if two `mountInfo` are equal.
func mountPointsEqual(a, b mountInfo) bool {
if a.Device != b.Device || a.Path != b.Path || a.FSType != b.FSType || !slicesEqual(a.Options, b.Options) || a.Pass != b.Pass || a.Freq != b.Freq {
return false
}
return true
}
// Checks if two string slices are equal.
func slicesEqual(a, b []string) bool {
if len(a) != len(b) {
return false
}
for i := range a {
if a[i] != b[i] {
return false
}
}
return true
}

View File

@@ -0,0 +1,31 @@
// +build !linux,!windows
// Copyright (c) 2015-2021 MinIO, Inc.
//
// This file is part of MinIO Object Storage stack
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package mountinfo
// CheckCrossDevice - check if any input path has multiple sub-mounts.
// this is a dummy function and returns nil for now.
func CheckCrossDevice(paths []string) error {
return nil
}
// IsLikelyMountPoint determines if a directory is a mountpoint.
func IsLikelyMountPoint(file string) bool {
return false
}

View File

@@ -0,0 +1,62 @@
// +build windows
// Copyright (c) 2015-2021 MinIO, Inc.
//
// This file is part of MinIO Object Storage stack
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package mountinfo
import (
"path/filepath"
"sync"
"golang.org/x/sys/windows"
)
// CheckCrossDevice - check if any input path has multiple sub-mounts.
// this is a dummy function and returns nil for now.
func CheckCrossDevice(paths []string) error {
return nil
}
// mountPointCache contains results of IsLikelyMountPoint
var mountPointCache sync.Map
// IsLikelyMountPoint determines if a directory is a mountpoint.
func IsLikelyMountPoint(path string) bool {
path = filepath.Dir(path)
if v, ok := mountPointCache.Load(path); ok {
return v.(bool)
}
wpath, _ := windows.UTF16PtrFromString(path)
wvolume := make([]uint16, len(path)+1)
if err := windows.GetVolumePathName(wpath, &wvolume[0], uint32(len(wvolume))); err != nil {
mountPointCache.Store(path, false)
return false
}
switch windows.GetDriveType(&wvolume[0]) {
case windows.DRIVE_FIXED, windows.DRIVE_REMOVABLE, windows.DRIVE_REMOTE, windows.DRIVE_RAMDISK:
// Recognize "fixed", "removable", "remote" and "ramdisk" drives as proper drives
// which can be treated as an actual mount-point, rest can be ignored.
// https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-getdrivetypew
mountPointCache.Store(path, true)
return true
}
mountPointCache.Store(path, false)
return false
}