blob: 085e6c3d5393b017224d261c324e295c85e850b5 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use {
crate::file_target::FileBlockingTarget,
crate::target::{AvailableTargets, Error, Target, TargetOps},
libc::c_void,
log::debug,
std::{ops::Range, os::unix::io::RawFd, result::Result, sync::Arc, time::Instant},
};
pub fn pread(raw_fd: RawFd, buffer: &mut Vec<u8>, offset: i64) -> Result<(), Error> {
let ret =
unsafe { libc::pread(raw_fd, buffer.as_mut_ptr() as *mut c_void, buffer.len(), offset) };
debug!("safe_pread: {:?} {}", offset, ret);
if ret < 0 {
return Err(Error::DoIoError(std::io::Error::last_os_error().kind()));
} else if ret < buffer.len() as isize {
return Err(Error::ShortRead);
}
Ok(())
}
pub fn pwrite(raw_fd: RawFd, buffer: &mut Vec<u8>, offset: i64) -> Result<(), Error> {
let ret =
unsafe { libc::pwrite(raw_fd, buffer.as_ptr() as *const c_void, buffer.len(), offset) };
debug!("safe_pwrite: {:?} {}", offset, ret);
if ret < 0 {
return Err(Error::DoIoError(std::io::Error::last_os_error().kind()));
} else if ret < buffer.len() as isize {
// TODO(auradkar): Define a set of error codes to be used throughout the app.
return Err(Error::ShortWrite);
}
Ok(())
}
/// Based on the input args, create_target searches available Targets and
/// creates an appropriate Target trait.
pub fn create_target(
target_type: AvailableTargets,
id: u64,
name: String,
offset: Range<u64>,
start: Instant,
) -> Arc<Box<dyn Target + Send + Sync>> {
match target_type {
AvailableTargets::FileTarget => FileBlockingTarget::new(name, id, offset, start),
}
}
/// Returned allowed TargetOps for giver Target `target_type`.
/// Allowed are the operations for which generator can generate io packets.
/// There maybe operations *supported* by the target for which generator
/// is not allowed to generate IO packets.
pub fn allowed_ops(target_type: AvailableTargets) -> &'static TargetOps {
match target_type {
AvailableTargets::FileTarget => FileBlockingTarget::allowed_ops(),
}
}
#[cfg(test)]
mod tests {
use {
crate::common_operations::pwrite,
crate::target::Error,
std::{fs::File, fs::OpenOptions, io::ErrorKind, os::unix::io::AsRawFd},
};
#[test]
fn test_pwrite_error_write_to_read_only_file() {
let file_name =
"/tmp/odu-common_operations-test_pwrite_error_write_to_read_only_file-file01"
.to_string();
// Create a file in rw mode if it doesn't exists.
File::create(&file_name).unwrap();
// Open the file in read-only mode and try to write to it.
let f = OpenOptions::new().read(true).write(false).open(file_name).unwrap();
let mut buffer = vec![0; 100];
let ret = pwrite(f.as_raw_fd(), &mut buffer, 0);
assert!(ret.is_err());
assert_eq!(ret.err(), Some(Error::DoIoError(ErrorKind::Other)));
}
}