moby/oci/devices_linux.go
Sebastiaan van Stijn 0ee5518e76
oci: use filepath.WalkDir instead of filepath.Walk
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>
2022-10-09 17:21:04 +02:00

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)
}