Browse Source

Implemented ChunkedFile

master
Gitea 2 years ago
parent
commit
7dd6bcb7db
  1. 152
      src/fsys/file.rs
  2. 1
      src/nodes/mod.rs
  3. 0
      src/nodes/node.rs
  4. 14
      src/protocol/packets.rs

152
src/fsys/file.rs

@ -14,6 +14,10 @@ GNU Affero General Public License for more details.
*/
use crate::util::error::Error;
use std::io::SeekFrom;
use std::io::Seek;
use std::io::Write;
use std::io::Read;
pub struct ChunkedFile {
pub size: u128,
@ -23,19 +27,66 @@ pub struct ChunkedFile {
}
impl ChunkedFile {
pub fn new(path: &std::path::Path, chunksize: u128) -> Result<ChunkedFile, Error> {
fn empty() -> ChunkedFile {
return ChunkedFile{
size: 0,
chunk_size: 0,
chunks_amount: 0,
path: std::path::PathBuf::new(),
}
}
/// Create a new, ready-to-write chunked regular file
pub fn new(path: &std::path::Path, size: u128, chunk_size: u128) -> Result<ChunkedFile, Error> {
let file_handle: std::fs::File;
match std::fs::File::create(path) {
Ok(fh) => {
file_handle = fh;
}
Err(error) => {
return Err(
Error::new(format!("{}", error).as_str())
);
}
}
let mut new_chunked_file: ChunkedFile = ChunkedFile::empty();
// path
new_chunked_file.path = path.to_path_buf();
// resize file
match file_handle.set_len(size as u64) {
Ok(()) => {}
Err(error) => {
return Err(
Error::new(format!("could not resize \'{}\': {}", path.display(), error).as_str())
);
}
}
new_chunked_file.size = size;
// chunks
new_chunked_file.chunk_size = chunk_size;
if new_chunked_file.size % chunk_size != 0 {
new_chunked_file.chunks_amount = (new_chunked_file.size / chunk_size) + 1;
} else {
new_chunked_file.chunks_amount = new_chunked_file.size / chunk_size;
}
return Ok(new_chunked_file);
}
/// Create a new, ready-to-read chunked file from already existing regular file
pub fn from(path: &std::path::Path, chunk_size: u128) -> Result<ChunkedFile, Error> {
if !path.is_file() {
return Err(
Error::new(format!("\'{}\' does not exist or not a regular file", path.display()).as_str())
);
}
let mut new_chunked_file: ChunkedFile = ChunkedFile{
size: 0,
chunk_size: 0,
chunks_amount: 0,
path: std::path::Path::new("").to_path_buf(),
};
let mut new_chunked_file: ChunkedFile = ChunkedFile::empty();
// path
new_chunked_file.path = path.to_path_buf();
@ -53,17 +104,98 @@ impl ChunkedFile {
}
// chunks
new_chunked_file.chunk_size = chunksize;
new_chunked_file.chunks_amount = (new_chunked_file.size as f32 / chunksize as f32).ceil() as u128;
new_chunked_file.chunk_size = chunk_size;
if new_chunked_file.size % chunk_size != 0 {
new_chunked_file.chunks_amount = (new_chunked_file.size / chunk_size) + 1;
} else {
new_chunked_file.chunks_amount = new_chunked_file.size / chunk_size;
}
return Ok(new_chunked_file);
}
pub fn read_chunk(&self, buf: &[u8], chunk_no: u128) -> Option<Error> {
pub fn read_chunk(&self, buf: &mut [u8], chunk_no: u128) -> Option<Error> {
if chunk_no > self.chunks_amount {
return Some(Error::new("chunk number is bigger than there are chunks"));
}
if (buf.len() as u128) < self.chunk_size {
return Some(Error::new("buffer is too small to fit a chunk"));
}
// open underlying file
let mut file_handle: std::fs::File;
match std::fs::File::open(&self.path) {
Ok(fh) => {
file_handle = fh;
}
Err(error) => {
return Some(Error::new(format!("{}", error).as_str()));
}
}
// set position and read
let chunk_start_pos: u128 = self.chunk_size * chunk_no;
match file_handle.seek(SeekFrom::Start(chunk_start_pos as u64)) {
Ok(_) => {}
Err(error) => {
return Some(Error::new(format!("seek error: {}", error).as_str()))
}
}
match file_handle.read(buf) {
Ok(_) => {}
Err(error) => {
return Some(Error::new(format!("read error: {}", error).as_str()))
}
}
return None;
}
pub fn write_chunk(&mut self, chunk: &[u8], chunk_no: u128) -> Option<Error> {
if chunk_no > self.chunks_amount {
// can't write outsize of pre-determined boundaries of a file !
return Some(Error::new("chunk number is bigger than there are chunks"));
}
if (chunk.len() as u128) < self.chunk_size && chunk_no != self.chunks_amount {
// unfull chunk in the middle of a file
return Some(Error::new("cannot write unfull chunk in a not last position"));
}
if (chunk.len() as u128) > self.chunk_size {
// too big chunk
return Some(Error::new("chunk is too big"));
}
// open file and write a new chunk
let mut file_handle: std::fs::File;
match std::fs::File::options().truncate(false).write(true).create(true).open(&self.path) {
Ok(file) => {
file_handle = file;
}
Err(error) => {
return Some(Error::new(format!("{}", error).as_str()));
}
}
let chunk_start_pos: u128 = self.chunk_size * chunk_no;
match file_handle.seek(SeekFrom::Start(chunk_start_pos as u64)) {
Ok(_) => {}
Err(error) => {
return Some(Error::new(format!("seek error: {}", error).as_str()));
}
}
match file_handle.write_all(chunk) {
Ok(()) => {}
Err(error) => {
return Some(Error::new(format!("write error: {}", error).as_str()))
}
}
return None;
}
}

1
src/nodes/mod.rs

@ -0,0 +1 @@
pub mod node;

0
src/nodes/node.rs

14
src/protocol/packets.rs

@ -110,7 +110,7 @@ impl FileInfoPacket {
};
}
pub fn new(file: ChunkedFile, file_id: u128, rel_path: String) -> Result<FileInfoPacket, Error> {
pub fn new(file: &ChunkedFile, file_id: u128, rel_path: String) -> Result<FileInfoPacket, Error> {
let mut new_fileinfo_packet: FileInfoPacket = FileInfoPacket::empty();
// id
@ -175,6 +175,12 @@ impl Packet for FileInfoPacket {
}
fn from_bytes(&mut self, packet_bytes: Vec<u8>) -> Option<Error> {
if packet_bytes.len() < 16+16+16+16+1+1 {
return Some(
Error::new(format!("{} bytes is too small for a fileinfo packet to be valid", packet_bytes.len()).as_str()
));
}
// file id
self.file_id = read_u128_slice(&packet_bytes[0..16]);
@ -236,6 +242,12 @@ impl Packet for FileDataPacket {
}
fn from_bytes(&mut self, packet_bytes: Vec<u8>) -> Option<Error> {
if packet_bytes.len() < 16+16+16+1 {
return Some(
Error::new(format!("{} bytes is too small for a fileinfo packet to be valid", packet_bytes.len()).as_str()
));
}
// file id
self.file_id = read_u128_slice(&packet_bytes[0..16]);

Loading…
Cancel
Save