pub fn lfs_fs_traverse_(
lfs: *mut super::lfs::Lfs,
cb: Option<unsafe extern "C" fn(*mut core::ffi::c_void, crate::types::lfs_block_t) -> i32>,
data: *mut core::ffi::c_void,
includeorphans: bool,
) -> i32 {
use crate::dir::fetch::lfs_dir_fetch;
use crate::dir::traverse::lfs_dir_get;
use crate::error::LFS_ERR_CORRUPT;
use crate::file::ctz::lfs_ctz_traverse;
use crate::fs::mount::{lfs_tortoise_detectcycles, LfsTortoise};
use crate::lfs_type::lfs_type::{LFS_TYPE_CTZSTRUCT, LFS_TYPE_DIRSTRUCT};
use crate::tag::{lfs_mktag, lfs_tag_type3};
use crate::types::{lfs_block_t, LFS_BLOCK_NULL};
use crate::util::{lfs_pair_fromle32, lfs_pair_isnull};
if cb.is_none() {
return 0;
}
let cb = cb.unwrap();
unsafe {
let mut dir = crate::dir::LfsMdir {
pair: [0, 0],
rev: 0,
off: 0,
etag: 0,
count: 0,
erased: false,
split: false,
tail: [0, 1],
};
let mut tortoise = LfsTortoise {
pair: [LFS_BLOCK_NULL, LFS_BLOCK_NULL],
i: 1,
period: 1,
};
#[cfg(feature = "loop_limits")]
const MAX_TRAVERSE_TAIL: u32 = 512;
#[cfg(feature = "loop_limits")]
let mut iter: u32 = 0;
crate::lfs_trace!("fs_traverse: tail loop start");
while !lfs_pair_isnull(&dir.tail) {
#[cfg(feature = "loop_limits")]
{
if iter >= MAX_TRAVERSE_TAIL {
panic!(
"loop_limits: MAX_TRAVERSE_TAIL ({}) exceeded",
MAX_TRAVERSE_TAIL
);
}
if iter > 0 && iter.is_multiple_of(20) {
crate::lfs_trace!("fs_traverse: iter={} tail={:?}", iter, dir.tail);
}
iter += 1;
}
let err = lfs_tortoise_detectcycles(&dir, &mut tortoise);
if err < 0 {
return crate::lfs_err!(LFS_ERR_CORRUPT);
}
for i in 0..2 {
let err = cb(data, dir.tail[i]);
if err != 0 {
return crate::lfs_pass_err!(err);
}
}
crate::lfs_trace!("fs_traverse: fetch tail={:?} count={}", dir.tail, dir.count);
let err = lfs_dir_fetch(lfs, &mut dir, &dir.tail);
if err != 0 {
return crate::lfs_pass_err!(err);
}
for id in 0..dir.count {
let mut raw: [lfs_block_t; 2] = [0, 0];
let tag = lfs_dir_get(
lfs,
&dir,
lfs_mktag(0x700, 0x3ff, 0),
lfs_mktag(crate::lfs_type::lfs_type::LFS_TYPE_STRUCT, id as u32, 8),
raw.as_mut_ptr() as *mut core::ffi::c_void,
);
if tag < 0 {
if tag == crate::error::LFS_ERR_NOENT {
continue;
}
return tag;
}
lfs_pair_fromle32(&mut raw);
if u32::from(lfs_tag_type3(tag as u32)) == LFS_TYPE_CTZSTRUCT {
let err = lfs_ctz_traverse(
lfs,
core::ptr::null(),
&mut (*lfs).rcache,
raw[0],
raw[1],
Some(cb),
data,
);
if err != 0 {
return crate::lfs_pass_err!(err);
}
} else if includeorphans
&& u32::from(lfs_tag_type3(tag as u32)) == LFS_TYPE_DIRSTRUCT
{
#[allow(clippy::needless_range_loop)] for i in 0..2 {
let err = cb(data, raw[i]);
if err != 0 {
return crate::lfs_pass_err!(err);
}
}
}
}
}
use crate::dir::LfsMlist;
use crate::file::ctz::lfs_ctz_traverse;
use crate::file::LfsFile;
use crate::lfs_type::lfs_open_flags::{LFS_F_DIRTY, LFS_F_INLINE, LFS_F_WRITING};
use crate::lfs_type::lfs_type::LFS_TYPE_REG;
let mut m = (*lfs).mlist;
#[cfg(feature = "loop_limits")]
const MAX_MLIST: u32 = 64;
#[cfg(feature = "loop_limits")]
let mut mlist_iter: u32 = 0;
while !m.is_null() {
#[cfg(feature = "loop_limits")]
{
if mlist_iter >= MAX_MLIST {
panic!("loop_limits: MAX_MLIST ({}) exceeded", MAX_MLIST);
}
mlist_iter += 1;
}
let f = m as *mut LfsFile;
let f_ref = &*f;
if f_ref.type_ as u32 == LFS_TYPE_REG {
if (f_ref.flags as i32 & LFS_F_DIRTY) != 0
&& (f_ref.flags as i32 & LFS_F_INLINE) == 0
{
let err = lfs_ctz_traverse(
lfs,
&(*f).cache,
&mut (*lfs).rcache,
f_ref.ctz.head,
f_ref.ctz.size,
Some(cb),
data,
);
if err != 0 {
return crate::lfs_pass_err!(err);
}
}
if (f_ref.flags as i32 & LFS_F_WRITING) != 0
&& (f_ref.flags as i32 & LFS_F_INLINE) == 0
{
let err = lfs_ctz_traverse(
lfs,
&(*f).cache,
&mut (*lfs).rcache,
f_ref.block,
f_ref.pos,
Some(cb),
data,
);
if err != 0 {
return crate::lfs_pass_err!(err);
}
}
}
m = (*m).next;
}
0
}
}