loopback.go 1.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. //go:build linux && cgo
  2. // +build linux,cgo
  3. package loopback // import "github.com/docker/docker/pkg/loopback"
  4. import (
  5. "fmt"
  6. "os"
  7. "github.com/sirupsen/logrus"
  8. "golang.org/x/sys/unix"
  9. )
  10. func getLoopbackBackingFile(file *os.File) (uint64, uint64, error) {
  11. loopInfo, err := unix.IoctlLoopGetStatus64(int(file.Fd()))
  12. if err != nil {
  13. logrus.Errorf("Error get loopback backing file: %s", err)
  14. return 0, 0, ErrGetLoopbackBackingFile
  15. }
  16. return loopInfo.Device, loopInfo.Inode, nil
  17. }
  18. // SetCapacity reloads the size for the loopback device.
  19. func SetCapacity(file *os.File) error {
  20. if err := unix.IoctlSetInt(int(file.Fd()), unix.LOOP_SET_CAPACITY, 0); err != nil {
  21. logrus.Errorf("Error loopbackSetCapacity: %s", err)
  22. return ErrSetCapacity
  23. }
  24. return nil
  25. }
  26. // FindLoopDeviceFor returns a loopback device file for the specified file which
  27. // is backing file of a loop back device.
  28. func FindLoopDeviceFor(file *os.File) *os.File {
  29. var stat unix.Stat_t
  30. err := unix.Stat(file.Name(), &stat)
  31. if err != nil {
  32. return nil
  33. }
  34. targetInode := stat.Ino
  35. targetDevice := uint64(stat.Dev) //nolint: unconvert // the type is 32bit on mips
  36. for i := 0; true; i++ {
  37. path := fmt.Sprintf("/dev/loop%d", i)
  38. file, err := os.OpenFile(path, os.O_RDWR, 0)
  39. if err != nil {
  40. if os.IsNotExist(err) {
  41. return nil
  42. }
  43. // Ignore all errors until the first not-exist
  44. // we want to continue looking for the file
  45. continue
  46. }
  47. dev, inode, err := getLoopbackBackingFile(file)
  48. if err == nil && dev == targetDevice && inode == targetInode {
  49. return file
  50. }
  51. file.Close()
  52. }
  53. return nil
  54. }