loopback.go 1.4 KB

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