Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ travis-ci = { repository = "serde-rs/serde" }
errno = "0.2"
libc = "0.2"

[build-dependencies]
bindgen = "0.58.1"

[dev-dependencies]
tempfile = "3.1.0"
lazy_static = "1.3.0"
Expand Down
18 changes: 18 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
extern crate bindgen;

use bindgen::Builder;
use std::{env::var, path::PathBuf};

fn main() {
let bindings = Builder::default()
.header_contents("wrapper.h", "#include <linux/loop.h>")
.derive_default(true)
.generate()
.expect("Could not generate bindings");

let mut bindings_path = PathBuf::from(var("OUT_DIR").unwrap());
bindings_path.push("bindings.rs");
bindings
.write_to_file(&bindings_path)
.expect("Could not write bindings to file");
}
113 changes: 43 additions & 70 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,27 +18,29 @@

extern crate libc;

use std::fs::File;
use std::fs::OpenOptions;

use bindings::{
loop_info64, LOOP_CLR_FD, LOOP_CTL_GET_FREE, LOOP_SET_CAPACITY, LOOP_SET_FD, LOOP_SET_STATUS64,
};
use libc::{c_int, ioctl};
use std::default::Default;
use std::io;
use std::os::unix::prelude::*;
use std::path::{Path, PathBuf};

// TODO support missing operations
const LOOP_SET_FD: u16 = 0x4C00;
const LOOP_CLR_FD: u16 = 0x4C01;
const LOOP_SET_STATUS64: u16 = 0x4C04;
//const LOOP_GET_STATUS64: u16 = 0x4C05;
const LOOP_SET_CAPACITY: u16 = 0x4C07;
//const LOOP_SET_DIRECT_IO: u16 = 0x4C08;
//const LOOP_SET_BLOCK_SIZE: u16 = 0x4C09;

//const LOOP_CTL_ADD: u16 = 0x4C80;
//const LOOP_CTL_REMOVE: u16 = 0x4C81;
const LOOP_CTL_GET_FREE: u16 = 0x4C82;
use std::fs::{File, OpenOptions};
use std::{
default::Default,
io,
os::unix::prelude::*,
path::{Path, PathBuf},
};

#[allow(non_camel_case_types)]
#[allow(dead_code)]
#[allow(non_snake_case)]
mod bindings {
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
}

#[cfg(not(target_os = "android"))]
type IoctlRequest = libc::c_ulong;
#[cfg(target_os = "android")]
type IoctlRequest = libc::c_int;

const LOOP_CONTROL: &str = "/dev/loop-control";
const LOOP_PREFIX: &str = "/dev/loop";
Expand Down Expand Up @@ -72,7 +74,10 @@ impl LoopControl {
/// ```
pub fn next_free(&self) -> io::Result<LoopDevice> {
let dev_num = ioctl_to_error(unsafe {
ioctl(self.dev_file.as_raw_fd() as c_int, LOOP_CTL_GET_FREE.into())
ioctl(
self.dev_file.as_raw_fd() as c_int,
LOOP_CTL_GET_FREE as IoctlRequest,
)
})?;
LoopDevice::open(&format!("{}{}", LOOP_PREFIX, dev_num))
}
Expand Down Expand Up @@ -124,7 +129,7 @@ impl LoopDevice {
note = "use `loop.with().offset(offset).attach(file)` instead"
)]
pub fn attach<P: AsRef<Path>>(&self, backing_file: P, offset: u64) -> io::Result<()> {
let info = LoopInfo64 {
let info = loop_info64 {
lo_offset: offset,
..Default::default()
};
Expand All @@ -145,7 +150,7 @@ impl LoopDevice {
/// # ld.detach().unwrap();
/// ```
pub fn attach_file<P: AsRef<Path>>(&self, backing_file: P) -> io::Result<()> {
let info = LoopInfo64 {
let info = loop_info64 {
..Default::default()
};

Expand All @@ -162,7 +167,7 @@ impl LoopDevice {
backing_file: P,
offset: u64,
) -> io::Result<()> {
let info = LoopInfo64 {
let info = loop_info64 {
lo_offset: offset,
..Default::default()
};
Expand All @@ -181,7 +186,7 @@ impl LoopDevice {
offset: u64,
size_limit: u64,
) -> io::Result<()> {
let info = LoopInfo64 {
let info = loop_info64 {
lo_offset: offset,
lo_sizelimit: size_limit,
..Default::default()
Expand All @@ -190,11 +195,11 @@ impl LoopDevice {
Self::attach_with_loop_info(self, backing_file, info)
}

/// Attach the loop device to a file with loop_info.
/// Attach the loop device to a file with loop_info64.
fn attach_with_loop_info(
&self, // TODO should be mut? - but changing it is a breaking change
backing_file: impl AsRef<Path>,
info: LoopInfo64,
info: loop_info64,
) -> io::Result<()> {
let bf = OpenOptions::new()
.read(true)
Expand All @@ -205,15 +210,15 @@ impl LoopDevice {
ioctl_to_error(unsafe {
ioctl(
self.device.as_raw_fd() as c_int,
LOOP_SET_FD.into(),
LOOP_SET_FD as IoctlRequest,
bf.as_raw_fd() as c_int,
)
})?;

if let Err(err) = ioctl_to_error(unsafe {
ioctl(
self.device.as_raw_fd() as c_int,
LOOP_SET_STATUS64.into(),
LOOP_SET_STATUS64 as IoctlRequest,
&info,
)
}) {
Expand Down Expand Up @@ -252,7 +257,13 @@ impl LoopDevice {
/// ld.detach().unwrap();
/// ```
pub fn detach(&self) -> io::Result<()> {
ioctl_to_error(unsafe { ioctl(self.device.as_raw_fd() as c_int, LOOP_CLR_FD.into(), 0) })?;
ioctl_to_error(unsafe {
ioctl(
self.device.as_raw_fd() as c_int,
LOOP_CLR_FD as IoctlRequest,
0,
)
})?;
Ok(())
}

Expand All @@ -262,7 +273,7 @@ impl LoopDevice {
ioctl_to_error(unsafe {
ioctl(
self.device.as_raw_fd() as c_int,
LOOP_SET_CAPACITY.into(),
LOOP_SET_CAPACITY as IoctlRequest,
0,
)
})?;
Expand Down Expand Up @@ -300,7 +311,7 @@ impl LoopDevice {
/// ```
pub struct AttachOptions<'d> {
device: &'d mut LoopDevice,
info: LoopInfo64,
info: loop_info64,
}

impl AttachOptions<'_> {
Expand Down Expand Up @@ -333,44 +344,6 @@ impl AttachOptions<'_> {
}
}

// https://man7.org/linux/man-pages/man4/loop.4.html
#[repr(C)]
struct LoopInfo64 {
pub lo_device: u64, // ioctl r/o
pub lo_inode: u64, // ioctl r/o
pub lo_rdevice: u64, // ioctl r/o
pub lo_offset: u64, //
pub lo_sizelimit: u64, // bytes, 0 == max available
pub lo_number: u32, // ioctl r/o
pub lo_encrypt_type: u32, //
pub lo_encrypt_key_size: u32, // ioctl w/o
pub lo_flags: u32, // ioctl r/w (r/o before Linux 2.6.25)
pub lo_file_name: [u8; 64], //
pub lo_crypt_name: [u8; 64], //
pub lo_encrypt_key: [u8; 32], // ioctl w/o
pub lo_init: [u64; 2], //
}

impl Default for LoopInfo64 {
fn default() -> Self {
Self {
lo_device: 0,
lo_inode: 0,
lo_rdevice: 0,
lo_offset: 0,
lo_sizelimit: 0,
lo_number: 0,
lo_encrypt_type: 0,
lo_encrypt_key_size: 0,
lo_flags: 0,
lo_file_name: [0; 64],
lo_crypt_name: [0; 64],
lo_encrypt_key: [0; 32],
lo_init: [0; 2],
}
}
}

fn ioctl_to_error(ret: i32) -> io::Result<i32> {
if ret < 0 {
Err(io::Error::last_os_error())
Expand Down
10 changes: 6 additions & 4 deletions tests/util/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use libc::fallocate;
use serde::{Deserialize, Deserializer};
use std::io;
use std::os::unix::io::AsRawFd;
use std::process::Command;
use std::sync::{Arc, Mutex, MutexGuard};
use std::{
io,
os::unix::io::AsRawFd,
process::Command,
sync::{Arc, Mutex, MutexGuard},
};

use tempfile::{NamedTempFile, TempPath};

Expand Down