setupLoopDev attaches the backing file to the loop device and returns the file handle for the loop device. The caller is responsible for closing the file handle.
(backingFile, loopDev string, param LoopParams)
| 65 | // the file handle for the loop device. The caller is responsible for |
| 66 | // closing the file handle. |
| 67 | func setupLoopDev(backingFile, loopDev string, param LoopParams) (_ *os.File, retErr error) { |
| 68 | // 1. Open backing file and loop device |
| 69 | flags := os.O_RDWR |
| 70 | if param.Readonly { |
| 71 | flags = os.O_RDONLY |
| 72 | } |
| 73 | |
| 74 | back, err := os.OpenFile(backingFile, flags, 0) |
| 75 | if err != nil { |
| 76 | return nil, fmt.Errorf("could not open backing file: %s: %w", backingFile, err) |
| 77 | } |
| 78 | defer back.Close() |
| 79 | |
| 80 | loop, err := os.OpenFile(loopDev, flags, 0) |
| 81 | if err != nil { |
| 82 | return nil, fmt.Errorf("could not open loop device: %s: %w", loopDev, err) |
| 83 | } |
| 84 | defer func() { |
| 85 | if retErr != nil { |
| 86 | loop.Close() |
| 87 | } |
| 88 | }() |
| 89 | |
| 90 | fiveDotEight := kernel.KernelVersion{Kernel: 5, Major: 8} |
| 91 | if ok, err := kernel.GreaterEqualThan(fiveDotEight); err == nil && ok { |
| 92 | config := unix.LoopConfig{ |
| 93 | Fd: uint32(back.Fd()), |
| 94 | } |
| 95 | |
| 96 | copy(config.Info.File_name[:], backingFile) |
| 97 | if param.Readonly { |
| 98 | config.Info.Flags |= unix.LO_FLAGS_READ_ONLY |
| 99 | } |
| 100 | |
| 101 | if param.Autoclear { |
| 102 | config.Info.Flags |= unix.LO_FLAGS_AUTOCLEAR |
| 103 | } |
| 104 | |
| 105 | if param.Direct { |
| 106 | config.Info.Flags |= unix.LO_FLAGS_DIRECT_IO |
| 107 | } |
| 108 | |
| 109 | if err := unix.IoctlLoopConfigure(int(loop.Fd()), &config); err != nil { |
| 110 | return nil, fmt.Errorf("failed to configure loop device: %s: %w", loopDev, err) |
| 111 | } |
| 112 | |
| 113 | return loop, nil |
| 114 | } |
| 115 | |
| 116 | // 2. Set FD |
| 117 | if err := unix.IoctlSetInt(int(loop.Fd()), unix.LOOP_SET_FD, int(back.Fd())); err != nil { |
| 118 | return nil, fmt.Errorf("could not set loop fd for device: %s: %w", loopDev, err) |
| 119 | } |
| 120 | |
| 121 | defer func() { |
| 122 | if retErr != nil { |
| 123 | _ = unix.IoctlSetInt(int(loop.Fd()), unix.LOOP_CLR_FD, 0) |
| 124 | } |