use crate::bd::bd::{lfs_bd_read, lfs_cache_drop, lfs_cache_zero};
use crate::dir::traverse::lfs_dir_getread;
use crate::dir::LfsMdir;
use crate::file::ctz::lfs_ctz_find;
use crate::file::LfsFile;
use crate::lfs_info::LfsFileConfig;
use crate::lfs_type::lfs_open_flags::{
LFS_F_DIRTY, LFS_F_ERRED, LFS_F_INLINE, LFS_F_READING, LFS_F_WRITING, LFS_O_RDONLY,
};
use crate::lfs_type::lfs_type::LFS_TYPE_INLINESTRUCT;
use crate::tag::lfs_mktag;
use crate::types::LFS_BLOCK_INLINE;
use crate::types::{lfs_block_t, lfs_off_t, lfs_size_t};
use crate::util::lfs_min;
pub fn lfs_file_opencfg_(
lfs: *mut crate::fs::Lfs,
file: *mut LfsFile,
path: *const i8,
flags: i32,
cfg: *const LfsFileConfig,
) -> i32 {
use crate::block_alloc::alloc::lfs_alloc_ckpoint;
use crate::dir::find::lfs_dir_find;
use crate::dir::lfs_mlist::lfs_mlist_append;
use crate::dir::traverse::lfs_dir_get;
use crate::error::{
LFS_ERR_EXIST, LFS_ERR_ISDIR, LFS_ERR_NAMETOOLONG, LFS_ERR_NOENT, LFS_ERR_NOMEM,
LFS_ERR_NOSPC,
};
use crate::file::lfs_ctz::lfs_ctz_fromle32;
use crate::fs::superblock::lfs_fs_forceconsistency;
use crate::lfs_info::LfsAttr;
use crate::lfs_type::lfs_open_flags::{LFS_O_CREAT, LFS_O_EXCL, LFS_O_TRUNC, LFS_O_WRONLY};
use crate::lfs_type::lfs_type::{LFS_TYPE_CREATE, LFS_TYPE_REG, LFS_TYPE_USERATTR};
use crate::tag::{lfs_mktag, lfs_tag_size, lfs_tag_type3};
use crate::types::LFS_BLOCK_INLINE;
use crate::util::{
lfs_min, lfs_path_isdir, lfs_path_islast, lfs_path_namelen, lfs_path_slice_from_cstr,
};
let path_u8 = path as *const u8;
unsafe {
if (flags & 2) != 0 {
let err = lfs_fs_forceconsistency(lfs);
if err != 0 {
return crate::lfs_pass_err!(err);
}
}
let file_ref = &mut *file;
file_ref.cfg = cfg;
file_ref.flags = flags as u32;
file_ref.pos = 0;
file_ref.off = 0;
file_ref.cache.buffer = core::ptr::null_mut();
let mut path_ptr = path_u8;
let mut tag = lfs_dir_find(lfs, &mut file_ref.m, &mut path_ptr, &mut file_ref.id);
if tag < 0 && !(tag == LFS_ERR_NOENT && lfs_path_islast(lfs_path_slice_from_cstr(path_ptr)))
{
let err = tag;
lfs_file_close_(lfs, file);
return crate::lfs_pass_err!(err);
}
file_ref.type_ = LFS_TYPE_REG as u8;
lfs_mlist_append(lfs, file as *mut crate::dir::LfsMlist);
if tag == LFS_ERR_NOENT {
if (flags & LFS_O_CREAT) == 0 {
lfs_file_close_(lfs, file);
return crate::lfs_err!(LFS_ERR_NOENT);
}
if lfs_path_isdir(lfs_path_slice_from_cstr(path_ptr)) {
lfs_file_close_(lfs, file);
return crate::error::LFS_ERR_NOTDIR;
}
let nlen = lfs_path_namelen(lfs_path_slice_from_cstr(path_ptr));
if nlen > (*lfs).name_max {
lfs_file_close_(lfs, file);
return crate::lfs_err!(LFS_ERR_NAMETOOLONG);
}
unsafe { lfs_alloc_ckpoint(lfs) };
let attrs = [
crate::tag::lfs_mattr {
tag: lfs_mktag(LFS_TYPE_CREATE, file_ref.id as u32, 0),
buffer: core::ptr::null(),
},
crate::tag::lfs_mattr {
tag: lfs_mktag(LFS_TYPE_REG, file_ref.id as u32, nlen),
buffer: path_ptr as *const core::ffi::c_void,
},
crate::tag::lfs_mattr {
tag: lfs_mktag(LFS_TYPE_INLINESTRUCT, file_ref.id as u32, 0),
buffer: core::ptr::null(),
},
];
let err = crate::dir::commit::lfs_dir_commit(
lfs,
&mut file_ref.m,
attrs.as_ptr() as *const _,
3,
);
let err = if err == crate::error::LFS_ERR_NOSPC {
LFS_ERR_NAMETOOLONG
} else {
err
};
if err != 0 {
lfs_file_close_(lfs, file);
return crate::lfs_pass_err!(err);
}
} else if (flags & LFS_O_EXCL) != 0 {
lfs_file_close_(lfs, file);
return crate::lfs_err!(LFS_ERR_EXIST);
} else if u32::from(lfs_tag_type3(tag as u32)) != LFS_TYPE_REG {
lfs_file_close_(lfs, file);
return crate::lfs_err!(LFS_ERR_ISDIR);
} else if (flags & LFS_O_TRUNC) != 0 {
tag = lfs_mktag(LFS_TYPE_INLINESTRUCT, file_ref.id as u32, 0) as i32;
file_ref.flags |= LFS_F_DIRTY as u32;
} else {
let struct_tag = lfs_dir_get(
lfs,
&file_ref.m as *const _,
lfs_mktag(0x700, 0x3ff, 0),
lfs_mktag(
crate::lfs_type::lfs_type::LFS_TYPE_STRUCT,
file_ref.id as u32,
8,
),
&mut file_ref.ctz as *mut _ as *mut core::ffi::c_void,
);
if struct_tag < 0 {
lfs_file_close_(lfs, file);
return struct_tag;
}
tag = struct_tag;
lfs_ctz_fromle32(&mut file_ref.ctz);
}
if !cfg.is_null() && (*cfg).attr_count > 0 && !(*cfg).attrs.is_null() {
let attr_count = (*cfg).attr_count as usize;
for i in 0..attr_count {
let attr = &*(*cfg).attrs.add(i);
if (file_ref.flags as i32 & LFS_O_RDONLY) == LFS_O_RDONLY {
let res = lfs_dir_get(
lfs,
&file_ref.m as *const _,
lfs_mktag(0x7ff, 0x3ff, 0),
lfs_mktag(
LFS_TYPE_USERATTR + attr.type_ as u32,
file_ref.id as u32,
attr.size,
),
attr.buffer,
);
if res < 0 && res != LFS_ERR_NOENT {
lfs_file_close_(lfs, file);
return res;
}
}
if (file_ref.flags as i32 & LFS_O_WRONLY) == LFS_O_WRONLY {
if attr.size > (*lfs).attr_max {
lfs_file_close_(lfs, file);
return crate::lfs_err!(LFS_ERR_NOSPC);
}
file_ref.flags |= LFS_F_DIRTY as u32;
}
}
}
if !cfg.is_null() && !(*cfg).buffer.is_null() {
file_ref.cache.buffer = (*cfg).buffer as *mut u8;
} else {
#[cfg(feature = "alloc")]
{
file_ref.cache.buffer = crate::lfs_alloc_module::lfs_malloc(
(*lfs).cfg.as_ref().expect("cfg").cache_size,
);
}
#[cfg(not(feature = "alloc"))]
{
lfs_file_close_(lfs, file);
return crate::lfs_err!(LFS_ERR_NOMEM);
}
if file_ref.cache.buffer.is_null() {
lfs_file_close_(lfs, file);
return crate::lfs_err!(LFS_ERR_NOMEM);
}
}
lfs_cache_zero(lfs as *const crate::fs::Lfs, &mut file_ref.cache);
let tag_val = if tag == LFS_ERR_NOENT {
lfs_mktag(LFS_TYPE_INLINESTRUCT, 0, 0) as i32
} else {
tag
};
if u32::from(lfs_tag_type3(tag_val as u32)) == LFS_TYPE_INLINESTRUCT {
file_ref.ctz.head = LFS_BLOCK_INLINE;
file_ref.ctz.size = if tag_val == LFS_ERR_NOENT {
0
} else {
lfs_tag_size(tag_val as u32)
};
file_ref.flags |= LFS_F_INLINE as u32;
file_ref.cache.block = file_ref.ctz.head;
file_ref.cache.off = 0;
file_ref.cache.size = (*lfs).cfg.as_ref().expect("cfg").cache_size;
if file_ref.ctz.size > 0 {
let res = lfs_dir_get(
lfs,
&file_ref.m as *const _,
lfs_mktag(0x700, 0x3ff, 0),
lfs_mktag(
crate::lfs_type::lfs_type::LFS_TYPE_STRUCT,
file_ref.id as u32,
lfs_min(file_ref.cache.size, 0x3fe),
),
file_ref.cache.buffer as *mut core::ffi::c_void,
);
if res < 0 {
lfs_file_close_(lfs, file);
return res;
}
}
}
}
0
}
static LFS_FILE_DEFAULTS: LfsFileConfig = LfsFileConfig {
buffer: core::ptr::null_mut(),
attrs: core::ptr::null_mut(),
attr_count: 0,
};
pub fn lfs_file_open_(
lfs: *mut crate::fs::Lfs,
file: *mut LfsFile,
path: *const i8,
flags: i32,
) -> i32 {
lfs_file_opencfg_(lfs, file, path, flags, &LFS_FILE_DEFAULTS)
}
pub fn lfs_file_close_(lfs: *mut crate::fs::Lfs, file: *mut LfsFile) -> i32 {
use crate::dir::lfs_mlist::lfs_mlist_remove;
let err = lfs_file_sync_(lfs, file);
if err != 0 {
return crate::lfs_pass_err!(err);
}
unsafe {
lfs_mlist_remove(lfs, file as *mut crate::dir::LfsMlist);
let cfg = (*file).cfg;
if !cfg.is_null() && (*cfg).buffer.is_null() {
#[cfg(feature = "alloc")]
{
crate::lfs_alloc_module::lfs_free(
(*file).cache.buffer,
(*lfs).cfg.as_ref().expect("cfg").cache_size,
);
}
}
}
err
}
pub fn lfs_file_relocate(lfs: *mut crate::fs::Lfs, file: *mut LfsFile) -> i32 {
use crate::bd::bd::{lfs_bd_erase, lfs_bd_prog, lfs_bd_read, lfs_cache_drop, lfs_cache_zero};
use crate::block_alloc::alloc::{lfs_alloc, lfs_alloc_lookahead};
use crate::error::LFS_ERR_CORRUPT;
'relocate: loop {
unsafe {
let mut nblock: lfs_block_t = 0;
let err = lfs_alloc(lfs, &mut nblock);
if err != 0 {
return crate::lfs_pass_err!(err);
}
let err = lfs_bd_erase(lfs as *const crate::fs::Lfs, nblock);
if err != 0 {
if err == LFS_ERR_CORRUPT {
lfs_alloc_lookahead(lfs, nblock);
lfs_cache_drop(lfs, &mut (*lfs).pcache as *mut _);
continue 'relocate;
}
return crate::lfs_pass_err!(err);
}
let file_ref = &mut *file;
let lfs_ref = &mut *lfs;
for i in 0..file_ref.off {
let mut data: u8 = 0;
let err = if (file_ref.flags as i32 & LFS_F_INLINE) != 0 {
let gtag = lfs_mktag(LFS_TYPE_INLINESTRUCT, file_ref.id as u32, 0);
lfs_dir_getread(
lfs,
&file_ref.m,
core::ptr::null(),
&mut file_ref.cache,
file_ref.off - i,
lfs_mktag(0xfff, 0x1ff, 0),
gtag,
i,
&mut data as *mut u8 as *mut core::ffi::c_void,
1,
)
} else {
lfs_bd_read(
lfs,
&file_ref.cache,
&mut lfs_ref.rcache,
file_ref.off - i,
file_ref.block,
i,
&mut data,
1,
)
};
if err != 0 {
return crate::lfs_pass_err!(err);
}
let err = lfs_bd_prog(
lfs as *const crate::fs::Lfs,
&mut lfs_ref.pcache,
&mut lfs_ref.rcache,
true,
nblock,
i,
&data,
1,
);
if err != 0 {
if err == LFS_ERR_CORRUPT {
lfs_alloc_lookahead(lfs, nblock);
lfs_cache_drop(lfs, &mut (*lfs).pcache as *mut _);
continue 'relocate;
}
return crate::lfs_pass_err!(err);
}
}
{
let lfs_ref = &mut *lfs;
let pcache = &lfs_ref.pcache;
let file_ref = &mut *file;
if !file_ref.cache.buffer.is_null() && !pcache.buffer.is_null() {
let cache_size = lfs_ref.cfg.as_ref().expect("cfg").cache_size as usize;
core::ptr::copy_nonoverlapping(
pcache.buffer,
file_ref.cache.buffer,
cache_size,
);
}
file_ref.cache.block = pcache.block;
file_ref.cache.off = pcache.off;
file_ref.cache.size = pcache.size;
file_ref.block = nblock;
file_ref.flags |= LFS_F_WRITING as u32;
}
lfs_cache_zero(lfs, &mut (*lfs).pcache as *mut _);
return 0;
}
}
}
pub fn lfs_file_outline(lfs: *mut crate::fs::Lfs, file: *mut LfsFile) -> i32 {
use crate::block_alloc::alloc::lfs_alloc_ckpoint;
unsafe {
let file_ref = &mut *file;
file_ref.off = file_ref.pos;
}
unsafe { lfs_alloc_ckpoint(lfs) };
let err = lfs_file_relocate(lfs, file);
if err != 0 {
return crate::lfs_pass_err!(err);
}
unsafe {
(*file).flags &= !LFS_F_INLINE as u32;
}
0
}
pub fn lfs_file_flush(lfs: *const core::ffi::c_void, file: *mut LfsFile) -> i32 {
use crate::bd::bd::lfs_bd_flush;
use crate::error::LFS_ERR_CORRUPT;
use crate::util::lfs_max;
unsafe {
let lfs = lfs as *mut crate::fs::Lfs;
let file_ref = &mut *file;
if (file_ref.flags as i32 & LFS_F_READING) != 0 {
if (file_ref.flags as i32 & LFS_F_INLINE) == 0 {
lfs_cache_drop(lfs as *const crate::fs::Lfs, &mut file_ref.cache);
}
file_ref.flags &= !(LFS_F_READING as u32);
}
if (file_ref.flags as i32 & LFS_F_WRITING) != 0 {
let pos = file_ref.pos;
if (file_ref.flags as i32 & LFS_F_INLINE) != 0 {
file_ref.pos = lfs_max(pos, file_ref.ctz.size);
} else {
let lfs_ref = &mut *lfs;
let mut orig = LfsFile {
next: core::ptr::null_mut(),
id: file_ref.id,
type_: file_ref.type_,
m: core::mem::zeroed(),
ctz: crate::file::lfs_ctz::LfsCtz {
head: file_ref.ctz.head,
size: file_ref.ctz.size,
},
flags: LFS_O_RDONLY as u32,
pos: file_ref.pos,
block: 0,
off: 0,
cache: core::ptr::read(&lfs_ref.rcache),
cfg: core::ptr::null(),
};
lfs_cache_drop(lfs as *const crate::fs::Lfs, &mut (*lfs).rcache);
#[allow(clippy::while_immutable_condition)] while (*file).pos < (*file).ctz.size {
let mut data: u8 = 0;
let res = lfs_file_flushedread(
lfs,
&mut orig,
&mut data as *mut u8 as *mut core::ffi::c_void,
1,
);
if res < 0 {
return res as i32;
}
let res = lfs_file_flushedwrite(
lfs,
file,
&data as *const u8 as *const core::ffi::c_void,
1,
);
if res < 0 {
return res as i32;
}
if (*lfs).rcache.block != crate::types::LFS_BLOCK_NULL {
lfs_cache_drop(lfs as *const crate::fs::Lfs, &mut orig.cache);
lfs_cache_drop(lfs as *const crate::fs::Lfs, &mut (*lfs).rcache);
}
}
'flush: loop {
let err = lfs_bd_flush(lfs, &mut (*file).cache, &mut (*lfs).rcache, true);
if err != 0 {
if err == LFS_ERR_CORRUPT {
let err = lfs_file_relocate(lfs, file);
if err != 0 {
return crate::lfs_pass_err!(err);
}
continue 'flush;
}
return crate::lfs_pass_err!(err);
}
break;
}
}
file_ref.ctz.head = file_ref.block;
file_ref.ctz.size = file_ref.pos;
file_ref.flags &= !(LFS_F_WRITING as u32);
file_ref.flags |= LFS_F_DIRTY as u32;
file_ref.pos = pos;
}
}
0
}
pub fn lfs_file_sync_(lfs: *mut crate::fs::Lfs, file: *mut LfsFile) -> i32 {
use crate::dir::commit::lfs_dir_commit;
use crate::fs::superblock::lfs_fs_deorphan;
use crate::tag::lfs_mktag;
use crate::types::LFS_BLOCK_INLINE;
use crate::util::lfs_pair_isnull;
unsafe {
let file_ref = &mut *file;
if (file_ref.flags as i32 & 0x080000) != 0 {
return 0;
}
let err = lfs_file_flush(lfs as *const core::ffi::c_void, file);
if err != 0 {
file_ref.flags |= 0x080000;
return crate::lfs_pass_err!(err);
}
if (file_ref.flags as i32 & 0x010000) != 0 && !lfs_pair_isnull(&file_ref.m.pair) {
let lfs_ref = &*lfs;
let cfg = lfs_ref.cfg.as_ref().expect("cfg");
if (file_ref.flags as i32 & LFS_F_INLINE) == 0 {
let err =
crate::bd::bd::lfs_bd_sync(lfs, &mut (*lfs).pcache, &mut (*lfs).rcache, false);
if err != 0 {
return crate::lfs_pass_err!(err);
}
}
let mut ctz = file_ref.ctz;
let (type_, buffer, size) = if (file_ref.flags as i32 & LFS_F_INLINE) != 0 {
(
LFS_TYPE_INLINESTRUCT,
file_ref.cache.buffer as *const core::ffi::c_void,
file_ref.ctz.size,
)
} else {
crate::file::lfs_ctz::lfs_ctz_tole32(&mut ctz);
(
crate::lfs_type::lfs_type::LFS_TYPE_CTZSTRUCT,
&ctz as *const _ as *const core::ffi::c_void,
core::mem::size_of::<crate::file::LfsCtz>() as u32,
)
};
let attrs = [
crate::tag::lfs_mattr {
tag: lfs_mktag(type_, file_ref.id as u32, size),
buffer,
},
crate::tag::lfs_mattr {
tag: lfs_mktag(
crate::lfs_type::lfs_type::LFS_FROM_USERATTRS,
file_ref.id as u32,
file_ref.cfg.as_ref().map_or(0, |c| c.attr_count),
) as u32,
buffer: file_ref.cfg.as_ref().map_or(core::ptr::null(), |c| c.attrs)
as *const core::ffi::c_void,
},
];
let err = lfs_dir_commit(lfs, &mut file_ref.m, attrs.as_ptr() as *const _, 2);
if err != 0 {
file_ref.flags |= 0x080000;
return crate::lfs_pass_err!(err);
}
file_ref.flags &= !0x010000;
}
}
0
}
pub fn lfs_file_flushedread(
lfs: *mut crate::fs::Lfs,
file: *mut LfsFile,
buffer: *mut core::ffi::c_void,
size: lfs_size_t,
) -> crate::types::lfs_ssize_t {
if buffer.is_null() {
return 0;
}
let data = buffer as *mut u8;
unsafe {
let file_ref = &mut *file;
let lfs_ref = &*lfs;
let cfg = lfs_ref.cfg.as_ref().expect("cfg");
let block_size = cfg.block_size;
if file_ref.pos >= file_ref.ctz.size {
return 0;
}
let size = lfs_min(size, file_ref.ctz.size - file_ref.pos);
let mut nsize = size;
let mut data = data;
while nsize > 0 {
if (file_ref.flags as i32 & LFS_F_READING) == 0 || file_ref.off == block_size {
if (file_ref.flags as i32 & LFS_F_INLINE) == 0 {
let err = lfs_ctz_find(
lfs,
core::ptr::null(),
&mut file_ref.cache,
file_ref.ctz.head,
file_ref.ctz.size,
file_ref.pos,
&mut file_ref.block,
&mut file_ref.off,
);
if err != 0 {
return err as crate::types::lfs_ssize_t;
}
} else {
file_ref.block = LFS_BLOCK_INLINE;
file_ref.off = file_ref.pos;
}
file_ref.flags |= LFS_F_READING as u32;
}
let diff = lfs_min(nsize, block_size - file_ref.off);
if (file_ref.flags as i32 & LFS_F_INLINE) != 0 {
let gtag = lfs_mktag(LFS_TYPE_INLINESTRUCT, file_ref.id as u32, 0);
let err = lfs_dir_getread(
lfs,
&file_ref.m,
core::ptr::null(),
&mut file_ref.cache,
block_size,
lfs_mktag(0xfff, 0x1ff, 0),
gtag,
file_ref.off,
data as *mut core::ffi::c_void,
diff,
);
if err != 0 {
return err as crate::types::lfs_ssize_t;
}
} else {
let err = lfs_bd_read(
lfs,
core::ptr::null(),
&mut file_ref.cache,
block_size,
file_ref.block,
file_ref.off,
data,
diff,
);
if err != 0 {
return err as crate::types::lfs_ssize_t;
}
}
file_ref.pos += diff;
file_ref.off += diff;
data = data.add(diff as usize);
nsize -= diff;
}
size as crate::types::lfs_ssize_t
}
}
pub fn lfs_file_read_(
lfs: *mut crate::fs::Lfs,
file: *mut LfsFile,
buffer: *mut core::ffi::c_void,
size: lfs_size_t,
) -> crate::types::lfs_ssize_t {
crate::lfs_assert!((unsafe { (*file).flags as i32 } & LFS_O_RDONLY) == LFS_O_RDONLY);
unsafe {
if ((*file).flags as i32 & LFS_F_WRITING) != 0 {
let err = lfs_file_flush(lfs as *const core::ffi::c_void, file);
if err != 0 {
return err as crate::types::lfs_ssize_t;
}
}
}
lfs_file_flushedread(lfs, file, buffer, size)
}
pub fn lfs_file_flushedwrite(
lfs: *mut crate::fs::Lfs,
file: *mut LfsFile,
buffer: *const core::ffi::c_void,
size: lfs_size_t,
) -> crate::types::lfs_ssize_t {
use crate::bd::bd::{lfs_bd_prog, lfs_cache_zero};
use crate::block_alloc::alloc::lfs_alloc_ckpoint;
use crate::error::LFS_ERR_CORRUPT;
use crate::file::ctz::{lfs_ctz_extend, lfs_ctz_find};
if buffer.is_null() {
return 0;
}
let data = buffer as *const u8;
unsafe {
let file_ref = &mut *file;
let lfs_ref = &*lfs;
let cfg = lfs_ref.cfg.as_ref().expect("cfg");
let block_size = cfg.block_size;
let mut nsize = size;
if (file_ref.flags as i32 & LFS_F_INLINE) != 0
&& crate::util::lfs_max(file_ref.pos + nsize, file_ref.ctz.size) > lfs_ref.inline_max
{
let err = lfs_file_outline(lfs, file);
if err != 0 {
file_ref.flags |= LFS_F_ERRED as u32;
return err as crate::types::lfs_ssize_t;
}
}
let mut data = data;
while nsize > 0 {
if (file_ref.flags as i32 & LFS_F_WRITING) == 0 || file_ref.off == block_size {
if (file_ref.flags as i32 & LFS_F_INLINE) != 0 {
file_ref.block = LFS_BLOCK_INLINE;
file_ref.off = file_ref.pos;
} else {
if (file_ref.flags as i32 & LFS_F_WRITING) == 0 && file_ref.pos > 0 {
let mut block_off: lfs_off_t = 0;
let err = lfs_ctz_find(
lfs,
core::ptr::null(),
&mut (*lfs).rcache,
file_ref.ctz.head,
file_ref.ctz.size,
file_ref.pos - 1,
&mut file_ref.block,
&mut block_off,
);
if err != 0 {
file_ref.flags |= LFS_F_ERRED as u32;
return err as crate::types::lfs_ssize_t;
}
lfs_cache_zero(lfs, &mut file_ref.cache as *mut _);
}
unsafe { lfs_alloc_ckpoint(lfs) };
let err = lfs_ctz_extend(
lfs,
&mut (*file).cache,
&mut (*lfs).rcache,
(*file).block,
(*file).pos,
&mut (*file).block,
&mut (*file).off,
);
if err != 0 {
file_ref.flags |= LFS_F_ERRED as u32;
return err as crate::types::lfs_ssize_t;
}
}
file_ref.flags |= LFS_F_WRITING as u32;
}
let diff = lfs_min(nsize, block_size - file_ref.off);
'prog: loop {
let err = lfs_bd_prog(
lfs,
&mut file_ref.cache,
&mut (*lfs).rcache,
true,
file_ref.block,
file_ref.off,
data,
diff,
);
if err != 0 {
if err == LFS_ERR_CORRUPT {
let err = lfs_file_relocate(lfs, file);
if err != 0 {
file_ref.flags |= LFS_F_ERRED as u32;
return err as crate::types::lfs_ssize_t;
}
continue 'prog;
}
file_ref.flags |= LFS_F_ERRED as u32;
return err as crate::types::lfs_ssize_t;
}
break;
}
file_ref.pos += diff;
file_ref.off += diff;
data = data.add(diff as usize);
nsize -= diff;
unsafe { lfs_alloc_ckpoint(lfs) };
}
size as crate::types::lfs_ssize_t
}
}
pub fn lfs_file_write_(
lfs: *mut crate::fs::Lfs,
file: *mut LfsFile,
buffer: *const core::ffi::c_void,
size: lfs_size_t,
) -> crate::types::lfs_ssize_t {
crate::lfs_assert!((unsafe { (*file).flags as i32 } & 2) == 2);
unsafe {
if ((*file).flags as i32 & LFS_F_READING) != 0 {
let err = lfs_file_flush(lfs as *const core::ffi::c_void, file);
if err != 0 {
return err as crate::types::lfs_ssize_t;
}
}
if ((*file).flags as i32 & 0x0800) != 0 && (*file).pos < (*file).ctz.size {
(*file).pos = (*file).ctz.size;
}
if (*file).pos + size > (*lfs).file_max {
return crate::error::LFS_ERR_FBIG as crate::types::lfs_ssize_t;
}
if ((*file).flags as i32 & LFS_F_WRITING) == 0 && (*file).pos > (*file).ctz.size {
let pos = (*file).pos;
(*file).pos = (*file).ctz.size;
let zero: u8 = 0;
#[allow(clippy::while_immutable_condition)] while (*file).pos < pos {
let res = lfs_file_flushedwrite(
lfs,
file,
&zero as *const u8 as *const core::ffi::c_void,
1,
);
if res < 0 {
return res;
}
}
}
let nsize = lfs_file_flushedwrite(lfs, file, buffer, size);
if nsize >= 0 {
(*file).flags &= !0x080000;
}
nsize
}
}
pub fn lfs_file_seek_(
lfs: *mut crate::fs::Lfs,
file: *mut LfsFile,
off: crate::types::lfs_soff_t,
whence: i32,
) -> crate::types::lfs_soff_t {
use crate::error::LFS_ERR_INVAL;
use crate::file::ctz::lfs_ctz_index;
use crate::lfs_type::lfs_whence_flags::{LFS_SEEK_CUR, LFS_SEEK_END, LFS_SEEK_SET};
unsafe {
let lfs_ref = &*lfs;
let file_ref = &mut *file;
let file_max = lfs_ref.file_max;
let block_size = lfs_ref.cfg.as_ref().expect("cfg").block_size;
let mut npos = file_ref.pos;
if whence == LFS_SEEK_SET {
npos = off as lfs_off_t;
} else if whence == LFS_SEEK_CUR {
npos = (file_ref.pos as i64 + off as i64) as lfs_off_t;
} else if whence == LFS_SEEK_END {
npos = (lfs_file_size_(lfs as *const core::ffi::c_void, file) as i64 + off as i64)
as lfs_off_t;
}
if npos > file_max {
return crate::lfs_err!(LFS_ERR_INVAL as crate::types::lfs_soff_t);
}
if file_ref.pos == npos {
return npos as crate::types::lfs_soff_t;
}
if (file_ref.flags as i32 & LFS_F_READING) != 0 && file_ref.off != block_size {
let mut opos = file_ref.pos;
let mut npos_off = npos;
let oindex = lfs_ctz_index(lfs as *const crate::fs::Lfs, &mut opos);
let nindex = lfs_ctz_index(lfs as *const crate::fs::Lfs, &mut npos_off);
if oindex == nindex
&& npos_off >= file_ref.cache.off
&& npos_off < file_ref.cache.off + file_ref.cache.size
{
file_ref.pos = npos;
file_ref.off = npos_off;
return npos as crate::types::lfs_soff_t;
}
}
let err = lfs_file_flush(lfs as *const core::ffi::c_void, file);
if err != 0 {
return err as crate::types::lfs_soff_t;
}
(*file).pos = npos;
npos as crate::types::lfs_soff_t
}
}
pub fn lfs_file_truncate_(lfs: *mut crate::fs::Lfs, file: *mut LfsFile, size: lfs_off_t) -> i32 {
use crate::error::LFS_ERR_INVAL;
use crate::file::ctz::lfs_ctz_find;
use crate::lfs_type::lfs_whence_flags::{LFS_SEEK_END, LFS_SEEK_SET};
crate::lfs_assert!((unsafe { (*file).flags as i32 } & 2) == 2);
unsafe {
let lfs_ref = &*lfs;
let file_ref = &mut *file;
if size > lfs_ref.file_max {
return crate::lfs_err!(LFS_ERR_INVAL);
}
let pos = file_ref.pos;
let oldsize = lfs_file_size_(lfs as *const core::ffi::c_void, file) as lfs_off_t;
if size < oldsize {
if size <= lfs_ref.inline_max {
let res = lfs_file_seek_(lfs, file, 0, LFS_SEEK_SET);
if res < 0 {
return res as i32;
}
crate::bd::bd::lfs_cache_drop(lfs, &mut (*lfs).rcache as *mut _);
let res = lfs_file_flushedread(
lfs,
file,
(*lfs).rcache.buffer as *mut core::ffi::c_void,
size,
);
if res < 0 {
return res as i32;
}
file_ref.ctz.head = LFS_BLOCK_INLINE;
file_ref.ctz.size = size;
file_ref.flags |= (LFS_F_DIRTY | LFS_F_READING | LFS_F_INLINE) as u32;
file_ref.cache.block = file_ref.ctz.head;
file_ref.cache.off = 0;
file_ref.cache.size = lfs_ref.cfg.as_ref().expect("cfg").cache_size;
core::ptr::copy_nonoverlapping(
(*lfs).rcache.buffer,
file_ref.cache.buffer,
size as usize,
);
} else {
let err = lfs_file_flush(lfs as *const core::ffi::c_void, file);
if err != 0 {
return crate::lfs_pass_err!(err);
}
let mut off_zero: lfs_off_t = 0;
let err = lfs_ctz_find(
lfs,
core::ptr::null(),
&mut file_ref.cache,
file_ref.ctz.head,
file_ref.ctz.size,
size.saturating_sub(1),
&mut file_ref.block,
&mut off_zero,
);
if err != 0 {
return crate::lfs_pass_err!(err);
}
file_ref.pos = size;
file_ref.ctz.head = file_ref.block;
file_ref.ctz.size = size;
file_ref.flags |= (LFS_F_DIRTY | LFS_F_READING) as u32;
}
} else if size > oldsize {
let res = lfs_file_seek_(lfs, file, 0, LFS_SEEK_END);
if res < 0 {
return res as i32;
}
let mut zero = 0u8;
#[allow(clippy::while_immutable_condition)] while file_ref.pos < size {
let res =
lfs_file_write_(lfs, file, &zero as *const u8 as *const core::ffi::c_void, 1);
if res < 0 {
return res as i32;
}
}
}
let res = lfs_file_seek_(lfs, file, pos as i32, LFS_SEEK_SET);
if res < 0 {
return res as i32;
}
}
0
}
pub fn lfs_file_tell_(
_lfs: *const core::ffi::c_void,
file: *const LfsFile,
) -> crate::types::lfs_soff_t {
unsafe { (*file).pos as crate::types::lfs_soff_t }
}
pub fn lfs_file_rewind_(lfs: *mut crate::fs::Lfs, file: *mut LfsFile) -> i32 {
let res = lfs_file_seek_(
lfs,
file,
0,
crate::lfs_type::lfs_whence_flags::LFS_SEEK_SET,
);
if res < 0 {
return res as i32;
}
0
}
pub fn lfs_file_size_(
_lfs: *const core::ffi::c_void,
file: *const LfsFile,
) -> crate::types::lfs_soff_t {
unsafe {
if ((*file).flags as i32 & LFS_F_WRITING) != 0 {
return crate::util::lfs_max((*file).pos, (*file).ctz.size) as crate::types::lfs_soff_t;
}
(*file).ctz.size as crate::types::lfs_soff_t
}
}