use crate::dir::fetch::{lfs_dir_fetch, lfs_dir_getinfo};
use crate::dir::find::lfs_dir_find;
use crate::dir::lfs_mlist::lfs_mlist_append;
use crate::dir::lfs_mlist::lfs_mlist_remove;
use crate::dir::traverse::lfs_dir_get;
use crate::dir::LfsDir;
use crate::lfs_info::LfsInfo;
use crate::lfs_type::lfs_type::LFS_TYPE_DIR;
use crate::tag::{lfs_mktag, lfs_tag_id, lfs_tag_type3};
use crate::types::lfs_off_t;
use crate::util::{lfs_min, lfs_pair_cmp, lfs_pair_fromle32};
pub fn lfs_dir_open_(lfs: *mut crate::fs::Lfs, dir: *mut LfsDir, path: *const u8) -> i32 {
if lfs.is_null() || dir.is_null() || path.is_null() {
return crate::error::LFS_ERR_INVAL;
}
unsafe {
let dir_ref = &mut *dir;
let mut path_ptr = path;
let tag = lfs_dir_find(lfs, &mut dir_ref.m, &mut path_ptr, core::ptr::null_mut());
if tag < 0 {
return tag;
}
if u32::from(lfs_tag_type3(tag as u32)) != LFS_TYPE_DIR {
return crate::error::LFS_ERR_NOTDIR;
}
let mut pair = [0u32; 2];
if lfs_tag_id(tag as u32) == 0x3ff {
pair[0] = (*lfs).root[0];
pair[1] = (*lfs).root[1];
} else {
let res = lfs_dir_get(
lfs,
&dir_ref.m as *const _,
lfs_mktag(0x700, 0x3ff, 0),
lfs_mktag(
crate::lfs_type::lfs_type::LFS_TYPE_STRUCT,
lfs_tag_id(tag as u32) as u32,
8,
),
pair.as_mut_ptr() as *mut core::ffi::c_void,
);
if res < 0 {
return res;
}
lfs_pair_fromle32(&mut pair);
}
let err = lfs_dir_fetch(lfs, &mut dir_ref.m, &pair);
if err != 0 {
return crate::lfs_pass_err!(err);
}
dir_ref.head[0] = dir_ref.m.pair[0];
dir_ref.head[1] = dir_ref.m.pair[1];
dir_ref.id = 0;
dir_ref.pos = 0;
dir_ref.type_ = LFS_TYPE_DIR as u8;
lfs_mlist_append(lfs, dir as *mut crate::dir::lfs_mlist::LfsMlist);
0
}
}
pub fn lfs_dir_close_(lfs: *mut crate::fs::Lfs, dir: *mut LfsDir) -> i32 {
if lfs.is_null() || dir.is_null() {
return crate::error::LFS_ERR_INVAL;
}
unsafe {
lfs_mlist_remove(lfs, dir as *mut crate::dir::lfs_mlist::LfsMlist);
}
0
}
pub fn lfs_dir_read_(lfs: *mut crate::fs::Lfs, dir: *mut LfsDir, info: *mut LfsInfo) -> i32 {
if lfs.is_null() || dir.is_null() || info.is_null() {
return crate::error::LFS_ERR_INVAL;
}
unsafe {
let dir_ref = &mut *dir;
let info_ref = &mut *info;
info_ref.type_ = 0;
info_ref.size = 0;
core::ptr::write_bytes(info_ref.name.as_mut_ptr(), 0, info_ref.name.len());
if dir_ref.pos == 0 {
info_ref.type_ = LFS_TYPE_DIR as u8;
info_ref.name[0] = b'.';
info_ref.name[1] = 0;
dir_ref.pos += 1;
return 1;
}
if dir_ref.pos == 1 {
info_ref.type_ = LFS_TYPE_DIR as u8;
info_ref.name[0] = b'.';
info_ref.name[1] = b'.';
info_ref.name[2] = 0;
dir_ref.pos += 1;
return 1;
}
#[cfg(feature = "loop_limits")]
const MAX_DIR_READ_ITER: u32 = 2048;
#[cfg(feature = "loop_limits")]
let mut iter: u32 = 0;
loop {
#[cfg(feature = "loop_limits")]
{
if iter >= MAX_DIR_READ_ITER {
panic!(
"loop_limits: MAX_DIR_READ_ITER ({}) exceeded",
MAX_DIR_READ_ITER
);
}
iter += 1;
}
if dir_ref.id == dir_ref.m.count {
if !dir_ref.m.split {
return 0;
}
let err = lfs_dir_fetch(lfs, &mut dir_ref.m, &dir_ref.m.tail);
if err != 0 {
return crate::lfs_pass_err!(err);
}
dir_ref.id = 0;
}
let err = lfs_dir_getinfo(lfs, &dir_ref.m, dir_ref.id, info);
if err != 0 && err != crate::error::LFS_ERR_NOENT {
return crate::lfs_pass_err!(err);
}
dir_ref.id += 1;
if err != crate::error::LFS_ERR_NOENT {
break;
}
}
dir_ref.pos += 1;
1
}
}
pub fn lfs_dir_seek_(lfs: *mut crate::fs::Lfs, dir: *mut LfsDir, off: lfs_off_t) -> i32 {
unsafe {
let err = lfs_dir_rewind_(lfs, dir);
if err != 0 {
return err;
}
let dir_ref = &mut *dir;
dir_ref.pos = lfs_min(2, off);
let mut off = off - dir_ref.pos;
dir_ref.id = if off > 0 && lfs_pair_cmp(&dir_ref.head, &(*lfs).root) == 0 {
1
} else {
0
};
while off > 0 {
if dir_ref.id == dir_ref.m.count {
if !dir_ref.m.split {
return crate::error::LFS_ERR_INVAL;
}
let err = lfs_dir_fetch(lfs, &mut dir_ref.m, &dir_ref.m.tail);
if err != 0 {
return err;
}
dir_ref.id = 0;
}
let diff = lfs_min((dir_ref.m.count - dir_ref.id) as u32, off);
dir_ref.id += diff as u16;
dir_ref.pos += diff;
off -= diff;
}
0
}
}
pub fn lfs_dir_tell_(_lfs: *mut crate::fs::Lfs, dir: *const LfsDir) -> crate::types::lfs_soff_t {
unsafe { (*dir).pos as crate::types::lfs_soff_t }
}
pub fn lfs_dir_rewind_(lfs: *mut crate::fs::Lfs, dir: *mut LfsDir) -> i32 {
unsafe {
let dir_ref = &mut *dir;
let err = lfs_dir_fetch(lfs, &mut dir_ref.m, &dir_ref.head);
if err != 0 {
return err;
}
dir_ref.id = 0;
dir_ref.pos = 0;
0
}
}