Skip to content

Commit

Permalink
Add AsyncFd::truncate
Browse files Browse the repository at this point in the history
Calls ftruncate(2), truncating a file to a specified length.
  • Loading branch information
Thomasdezeeuw committed Jul 20, 2024
1 parent 1777cd1 commit 6cd7447
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 3 deletions.
27 changes: 27 additions & 0 deletions src/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,17 @@ impl<D: Descriptor> AsyncFd<D> {
) -> Allocate<'fd, D> {
Allocate::new(self, (offset, length, mode))
}

/// Truncate the file to `length`.
///
/// If the file previously was larger than this size, the extra data is
/// lost. If the file previously was shorter, it is extended, and the
/// extended part reads as null bytes.
#[doc = man_link!(ftruncate(2))]
#[doc(alias = "ftruncate")]
pub const fn truncate<'fd>(&'fd self, length: u64) -> Truncate<'fd, D> {
Truncate::new(self, length)
}
}

// SyncData.
Expand Down Expand Up @@ -430,6 +441,22 @@ op_future! {
},
}

// Truncate.
op_future! {
fn AsyncFd::truncate -> (),
struct Truncate<'fd> {
// Doesn't need any fields.
},
setup_state: flags: u64,
setup: |submission, fd, (), length| unsafe {
submission.ftruncate(fd.fd(), length);
},
map_result: |this, (), res| {
debug_assert!(res == 0);
Ok(())
},
}

/// Metadata information about a file.
///
/// See [`AsyncFd::metadata`] and [`Stat`].
Expand Down
6 changes: 6 additions & 0 deletions src/op.rs
Original file line number Diff line number Diff line change
Expand Up @@ -745,6 +745,12 @@ impl Submission {
};
}

pub(crate) unsafe fn ftruncate(&mut self, fd: RawFd, offset: u64) {
self.inner.opcode = libc::IORING_OP_FTRUNCATE as u8;
self.inner.fd = fd;
self.inner.__bindgen_anon_1 = libc::io_uring_sqe__bindgen_ty_1 { off: offset };
}

pub(crate) unsafe fn wake(&mut self, ring_fd: RawFd) {
self.msg(ring_fd, u64::MAX, 0, 0);
self.no_completion_event();
Expand Down
44 changes: 41 additions & 3 deletions tests/async_fd/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ use std::path::{Path, PathBuf};
use std::{panic, str};

use a10::fd::File;
use a10::fs::{self, Advise, Allocate, CreateDir, Delete, Open, OpenOptions, Rename};
use a10::fs::{self, Advise, Allocate, CreateDir, Delete, Open, OpenOptions, Rename, Truncate};
use a10::io::{Read, ReadVectored, Write, WriteVectored};
use a10::{Extract, SubmissionQueue};

use crate::util::{
defer, is_send, is_sync, page_size, remove_test_dir, remove_test_file, test_queue, TestFile,
Waker, LOREM_IPSUM_5, LOREM_IPSUM_50,
defer, is_send, is_sync, page_size, remove_test_dir, remove_test_file, require_kernel,
test_queue, TestFile, Waker, LOREM_IPSUM_5, LOREM_IPSUM_50,
};

const DATA: &[u8] = b"Hello, World";
Expand Down Expand Up @@ -521,6 +521,44 @@ fn fadvise() {
assert!(buf == test_file.content, "read content is different");
}

#[test]
fn ftruncate() {
require_kernel!(6, 9);

let sq = test_queue();
let waker = Waker::new();

is_send::<Truncate>();
is_sync::<Truncate>();

let mut path = temp_dir();
path.push("ftruncate");
let _d = defer(|| remove_test_file(&path));

let open_file: Open<File> = OpenOptions::new()
.write()
.create()
.truncate()
.open(sq, path.clone());
let file = waker.block_on(open_file).unwrap();

waker
.block_on(file.write_all(LOREM_IPSUM_50.content))
.unwrap();

let metadata = waker.block_on(file.metadata()).unwrap();
assert_eq!(metadata.len(), LOREM_IPSUM_50.content.len() as u64);

const SIZE: u64 = 4096;

waker
.block_on(file.truncate(SIZE))
.expect("failed fallocate");

let metadata = waker.block_on(file.metadata()).unwrap();
assert_eq!(metadata.len(), SIZE);
}

#[test]
fn fallocate() {
let sq = test_queue();
Expand Down

0 comments on commit 6cd7447

Please sign in to comment.