2 use std
::fs
::{File, OpenOptions}
;
4 use std
::os
::unix
::io
::{RawFd, AsRawFd}
;
6 const LOOP_CONTROL
: &str = "/dev/loop-control";
7 const LOOP_NAME
: &str = "/dev/loop";
9 /// Implements a subset of loop device ioctls necessary to assign and release
10 /// a single file from a free loopdev.
12 use nix
::{ioctl_none, ioctl_write_int_bad, ioctl_write_ptr_bad}
;
14 const LOOP_IOCTL
: u16 = 0x4C; // 'L'
15 const LOOP_SET_FD
: u16 = 0x00;
16 const LOOP_CLR_FD
: u16 = 0x01;
17 const LOOP_SET_STATUS64
: u16 = 0x04;
19 const LOOP_CTRL_GET_FREE
: u16 = 0x82;
21 ioctl_write_int_bad
!(ioctl_set_fd
, (LOOP_IOCTL
<< 8) | LOOP_SET_FD
);
22 ioctl_none
!(ioctl_clr_fd
, LOOP_IOCTL
, LOOP_CLR_FD
);
23 ioctl_none
!(ioctl_ctrl_get_free
, LOOP_IOCTL
, LOOP_CTRL_GET_FREE
);
24 ioctl_write_ptr_bad
!(ioctl_set_status64
, (LOOP_IOCTL
<< 8) | LOOP_SET_STATUS64
, LoopInfo64
);
26 pub const LO_FLAGS_READ_ONLY
: u32 = 1;
27 pub const LO_FLAGS_PARTSCAN
: u32 = 8;
29 const LO_NAME_SIZE
: usize = 64;
30 const LO_KEY_SIZE
: usize = 32;
33 pub struct LoopInfo64
{
38 pub lo_sizelimit
: u64,
40 pub lo_encrypt_type
: u32,
41 pub lo_encrypt_key_size
: u32,
43 pub lo_file_name
: [u8; LO_NAME_SIZE
],
44 pub lo_crypt_name
: [u8; LO_NAME_SIZE
],
45 pub lo_encrypt_key
: [u8; LO_KEY_SIZE
],
46 pub lo_init
: [u64; 2],
50 // ioctl helpers create public fns, do not export them outside the module
51 // users should use the wrapper functions below
54 /// Use the GET_FREE ioctl to get or add a free loop device, of which the
55 /// /dev/loopN path will be returned. This is inherently racy because of the
56 /// delay between this and calling assign, but since assigning is atomic it
57 /// does not matter much and will simply cause assign to fail.
58 pub fn get_or_create_free_dev() -> Result
<String
, Error
> {
59 let ctrl_file
= File
::open(LOOP_CONTROL
)?
;
60 let free_num
= unsafe { ioctl_ctrl_get_free(ctrl_file.as_raw_fd())? }
;
61 let loop_file_path
= format
!("{}{}", LOOP_NAME
, free_num
);
65 fn assign_dev(fd
: RawFd
, backing_fd
: RawFd
) -> Result
<(), Error
> {
66 unsafe { ioctl_set_fd(fd, backing_fd)?; }
68 // set required read-only flag and partscan for convenience
69 let mut info
: LoopInfo64
= unsafe { std::mem::zeroed() }
;
70 info
.lo_flags
= LO_FLAGS_READ_ONLY
| LO_FLAGS_PARTSCAN
;
71 unsafe { ioctl_set_status64(fd, &info)?; }
76 /// Open the next available /dev/loopN file and assign the given path to
77 /// it as it's backing file in read-only mode.
78 pub fn assign
<P
: AsRef
<Path
>>(loop_dev
: P
, backing
: P
) -> Result
<(), Error
> {
79 let loop_file
= File
::open(loop_dev
)?
;
80 let backing_file
= OpenOptions
::new()
83 assign_dev(loop_file
.as_raw_fd(), backing_file
.as_raw_fd())?
;
87 /// Unassign any file descriptors currently attached to the given
88 /// /dev/loopN device.
89 pub fn unassign
<P
: AsRef
<Path
>>(path
: P
) -> Result
<(), Error
> {
90 let loop_file
= File
::open(path
)?
;
91 unsafe { ioctl_clr_fd(loop_file.as_raw_fd())?; }