func (v VolumePathHandler) GetDeviceBindMountRefs(ctx context.Context, devPath string, mapPath string) ([]string, error) {
	ctx, logger := pmemlog.WithName(ctx, "GetDeviceBindMountRefs")
	var refs []string
	files, err := ioutil.ReadDir(mapPath)
	if err != nil {
		return nil, fmt.Errorf("directory cannot read %v", err)
	}
	for _, file := range files {
		if file.Mode()&os.ModeDevice != os.ModeDevice {
			continue
		}
		filename := file.Name()
		refs = append(refs, filepath.Join(mapPath, filename))
	}
	logger.V(5).Info("Completed", "refs", refs)
	return refs, nil
}
GetDeviceBindMountRefs searches bind mounts under global map path
package volumepathhandler
import (
	"context"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"k8s.io/utils/exec"
	"k8s.io/utils/mount"
	"k8s.io/apimachinery/pkg/types"
	pmemlog "github.com/intel/pmem-csi/pkg/logger"
)
const (
	losetupPath           = "losetup"
	ErrDeviceNotFound     = "device not found"
	ErrDeviceNotSupported = "device not supported"
)
type BlockVolumePathHandler interface {
	MapDevice(ctx context.Context, devicePath string, mapPath string, linkName string, bindMount bool) error
	UnmapDevice(ctx context.Context, mapPath string, linkName string, bindMount bool) error
	RemoveMapPath(ctx context.Context, mapPath string) error
	IsSymlinkExist(ctx context.Context, mapPath string) (bool, error)
	IsDeviceBindMountExist(ctx context.Context, mapPath string) (bool, error)
	GetDeviceBindMountRefs(ctx context.Context, devPath string, mapPath string) ([]string, error)
	FindGlobalMapPathUUIDFromPod(ctx context.Context, pluginDir, mapPath string, podUID types.UID) (string, error)
	AttachFileDevice(ctx context.Context, path string) (string, error)
	DetachFileDevice(ctx context.Context, path string) error
	GetLoopDevice(ctx context.Context, path string) (string, error)
}
func NewBlockVolumePathHandler() BlockVolumePathHandler {
	var volumePathHandler VolumePathHandler
	return volumePathHandler
}
type VolumePathHandler struct {
}
func (v VolumePathHandler) MapDevice(ctx context.Context, devicePath string, mapPath string, linkName string, bindMount bool) error {
	ctx, logger := pmemlog.WithName(ctx, "MapDevice")
	if len(devicePath) == 0 {
		return fmt.Errorf("failed to map device to map path. devicePath is empty")
	}
	if len(mapPath) == 0 {
		return fmt.Errorf("failed to map device to map path. mapPath is empty")
	}
	if !filepath.IsAbs(mapPath) {
		return fmt.Errorf("the map path should be absolute: map path: %s", mapPath)
	}
	logger.V(5).Info("Setting up",
		"device-path", devicePath,
		"map-path", mapPath,
		"link-name", linkName,
	)
	_, err := os.Stat(mapPath)
	if err != nil && !os.IsNotExist(err) {
		return fmt.Errorf("cannot validate map path: %s: %v", mapPath, err)
	}
	if err = os.MkdirAll(mapPath, 0750); err != nil {
		return fmt.Errorf("failed to mkdir %s: %v", mapPath, err)
	}
	if bindMount {
		return mapBindMountDevice(ctx, v, devicePath, mapPath, linkName)
	}
	return mapSymlinkDevice(v, devicePath, mapPath, linkName)
}
func mapBindMountDevice(ctx context.Context, v VolumePathHandler, devicePath string, mapPath string, linkName string) error {
	ctx, logger := pmemlog.WithName(ctx, "mapBindMountDevice")
	linkPath := filepath.Join(mapPath, string(linkName))
	file, err := os.Stat(linkPath)
	if err != nil {
		if !os.IsNotExist(err) {
			return fmt.Errorf("failed to stat file %s: %v", linkPath, err)
		}
		newFile, err := os.OpenFile(linkPath, os.O_CREATE|os.O_RDWR, 0750)
		if err != nil {
			return fmt.Errorf("failed to open file %s: %v", linkPath, err)
		}
		if err := newFile.Close(); err != nil {
			return fmt.Errorf("failed to close file %s: %v", linkPath, err)
		}
	} else {
		if file.Mode()&os.ModeDevice == os.ModeDevice {
			logger.V(2).Info("Warning: Map skipped because bind mount already exist on the path", "link-path", linkPath)
			return nil
		}
		logger.V(2).Info("Warning: file already exists but is not mounted, skip creating file", "link-path", linkPath)
	}
	mounter := &mount.SafeFormatAndMount{Interface: mount.New(""), Exec: exec.New()}
	if err := mounter.Mount(devicePath, linkPath, ""  , []string{"bind"}); err != nil {
		return fmt.Errorf("failed to bind mount devicePath: %s to linkPath %s: %v", devicePath, linkPath, err)
	}
	return nil
}
func mapSymlinkDevice(v VolumePathHandler, devicePath string, mapPath string, linkName string) error {
	linkPath := filepath.Join(mapPath, string(linkName))
	if err := os.Remove(linkPath); err != nil && !os.IsNotExist(err) {
		return fmt.Errorf("failed to remove file %s: %v", linkPath, err)
	}
	return os.Symlink(devicePath, linkPath)
}
func (v VolumePathHandler) UnmapDevice(ctx context.Context, mapPath string, linkName string, bindMount bool) error {
	ctx, logger := pmemlog.WithName(ctx, "UnmapDevice")
	if len(mapPath) == 0 {
		return fmt.Errorf("failed to unmap device from map path. mapPath is empty")
	}
	logger.V(5).Info("Unmapping", "map-path", mapPath, "link-path", linkName)
	if bindMount {
		return unmapBindMountDevice(ctx, v, mapPath, linkName)
	}
	return unmapSymlinkDevice(ctx, v, mapPath, linkName)
}
func unmapBindMountDevice(ctx context.Context, v VolumePathHandler, mapPath string, linkName string) error {
	ctx, logger := pmemlog.WithName(ctx, "unmapBindMountDevice")
	linkPath := filepath.Join(mapPath, string(linkName))
	if isMountExist, checkErr := v.IsDeviceBindMountExist(ctx, linkPath); checkErr != nil {
		return checkErr
	} else if !isMountExist {
		logger.V(2).Info("Warning: Unmap skipped because bind mount does not exist on the path", "link-path", linkPath)
		if _, err := os.Stat(linkPath); err != nil {
			if !os.IsNotExist(err) {
				return fmt.Errorf("failed to check if path %s exists: %v", linkPath, err)
			}
			return nil
		}
		if err := os.Remove(linkPath); err != nil && !os.IsNotExist(err) {
			return fmt.Errorf("failed to remove file %s: %v", linkPath, err)
		}
		return nil
	}
	mounter := &mount.SafeFormatAndMount{Interface: mount.New(""), Exec: exec.New()}
	if err := mounter.Unmount(linkPath); err != nil {
		return fmt.Errorf("failed to unmount linkPath %s: %v", linkPath, err)
	}
	if err := os.Remove(linkPath); err != nil && !os.IsNotExist(err) {
		return fmt.Errorf("failed to remove file %s: %v", linkPath, err)
	}
	return nil
}
func unmapSymlinkDevice(ctx context.Context, v VolumePathHandler, mapPath string, linkName string) error {
	ctx, logger := pmemlog.WithName(ctx, "unmapSymlinkDevice")
	linkPath := filepath.Join(mapPath, string(linkName))
	if islinkExist, checkErr := v.IsSymlinkExist(ctx, linkPath); checkErr != nil {
		return checkErr
	} else if !islinkExist {
		logger.V(2).Info("Warning: Unmap skipped because symlink does not exist on the path", "link-path", linkPath)
		return nil
	}
	return os.Remove(linkPath)
}
func (v VolumePathHandler) RemoveMapPath(ctx context.Context, mapPath string) error {
	ctx, logger := pmemlog.WithName(ctx, "RemoveMapPath")
	if len(mapPath) == 0 {
		return fmt.Errorf("failed to remove map path. mapPath is empty")
	}
	logger.V(5).Info("Removing", "map-path", mapPath)
	err := os.RemoveAll(mapPath)
	if err != nil && !os.IsNotExist(err) {
		return fmt.Errorf("failed to remove directory %s: %v", mapPath, err)
	}
	return nil
}
func (v VolumePathHandler) IsSymlinkExist(ctx context.Context, mapPath string) (bool, error) {
	fi, err := os.Lstat(mapPath)
	if err != nil {
		if os.IsNotExist(err) {
			return false, nil
		}
		return false, fmt.Errorf("failed to Lstat file %s: %v", mapPath, err)
	}
	if fi.Mode()&os.ModeSymlink == os.ModeSymlink {
		return true, nil
	}
	return false, nil
}
func (v VolumePathHandler) IsDeviceBindMountExist(ctx context.Context, mapPath string) (bool, error) {
	fi, err := os.Lstat(mapPath)
	if err != nil {
		if os.IsNotExist(err) {
			return false, nil
		}
		return false, fmt.Errorf("failed to Lstat file %s: %v", mapPath, err)
	}
	if fi.Mode()&os.ModeDevice == os.ModeDevice {
		return true, nil
	}
	return false, nil
}