0ee5518e76
WalkDir is more performant as it doesn't perform an os.Lstat on every visited file or directory. Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
70 lines
2.2 KiB
Go
70 lines
2.2 KiB
Go
package oci // import "github.com/docker/docker/oci"
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
coci "github.com/containerd/containerd/oci"
|
|
specs "github.com/opencontainers/runtime-spec/specs-go"
|
|
)
|
|
|
|
func deviceCgroup(d *specs.LinuxDevice, permissions string) specs.LinuxDeviceCgroup {
|
|
return specs.LinuxDeviceCgroup{
|
|
Allow: true,
|
|
Type: d.Type,
|
|
Major: &d.Major,
|
|
Minor: &d.Minor,
|
|
Access: permissions,
|
|
}
|
|
}
|
|
|
|
// DevicesFromPath computes a list of devices and device permissions from paths (pathOnHost and pathInContainer) and cgroup permissions.
|
|
func DevicesFromPath(pathOnHost, pathInContainer, cgroupPermissions string) (devs []specs.LinuxDevice, devPermissions []specs.LinuxDeviceCgroup, err error) {
|
|
resolvedPathOnHost := pathOnHost
|
|
|
|
// check if it is a symbolic link
|
|
if src, e := os.Lstat(pathOnHost); e == nil && src.Mode()&os.ModeSymlink == os.ModeSymlink {
|
|
if linkedPathOnHost, e := filepath.EvalSymlinks(pathOnHost); e == nil {
|
|
resolvedPathOnHost = linkedPathOnHost
|
|
}
|
|
}
|
|
|
|
device, err := coci.DeviceFromPath(resolvedPathOnHost)
|
|
// if there was no error, return the device
|
|
if err == nil {
|
|
device.Path = pathInContainer
|
|
return append(devs, *device), append(devPermissions, deviceCgroup(device, cgroupPermissions)), nil
|
|
}
|
|
|
|
// if the device is not a device node
|
|
// try to see if it's a directory holding many devices
|
|
if err == coci.ErrNotADevice {
|
|
// check if it is a directory
|
|
if src, e := os.Stat(resolvedPathOnHost); e == nil && src.IsDir() {
|
|
// mount the internal devices recursively
|
|
// TODO check if additional errors should be handled or logged
|
|
_ = filepath.WalkDir(resolvedPathOnHost, func(dpath string, f os.DirEntry, _ error) error {
|
|
childDevice, e := coci.DeviceFromPath(dpath)
|
|
if e != nil {
|
|
// ignore the device
|
|
return nil
|
|
}
|
|
|
|
// add the device to userSpecified devices
|
|
childDevice.Path = strings.Replace(dpath, resolvedPathOnHost, pathInContainer, 1)
|
|
devs = append(devs, *childDevice)
|
|
devPermissions = append(devPermissions, deviceCgroup(childDevice, cgroupPermissions))
|
|
|
|
return nil
|
|
})
|
|
}
|
|
}
|
|
|
|
if len(devs) > 0 {
|
|
return devs, devPermissions, nil
|
|
}
|
|
|
|
return devs, devPermissions, fmt.Errorf("error gathering device information while adding custom device %q: %s", pathOnHost, err)
|
|
}
|