pub fn lfs_fs_pred(
lfs: *mut crate::fs::Lfs,
pair: &[crate::types::lfs_block_t; 2],
pdir: *mut crate::dir::LfsMdir,
) -> i32 {
use crate::dir::fetch::lfs_dir_fetch;
use crate::fs::mount::{lfs_tortoise_detectcycles, LfsTortoise};
use crate::types::LFS_BLOCK_NULL;
use crate::util::{lfs_pair_cmp, lfs_pair_isnull};
unsafe {
(*pdir).tail = [0, 1];
let mut tortoise = LfsTortoise {
pair: [LFS_BLOCK_NULL, LFS_BLOCK_NULL],
i: 1,
period: 1,
};
let mut have_fetched = false;
#[cfg(feature = "loop_limits")]
const MAX_PARENT_ITER: u32 = 2048;
#[cfg(feature = "loop_limits")]
let mut iter: u32 = 0;
while !lfs_pair_isnull(&(*pdir).tail) {
#[cfg(feature = "loop_limits")]
{
if iter >= MAX_PARENT_ITER {
panic!(
"loop_limits: MAX_PARENT_ITER ({}) exceeded in lfs_fs_parent",
MAX_PARENT_ITER
);
}
iter += 1;
}
let err = lfs_tortoise_detectcycles(pdir, &mut tortoise);
if err < 0 {
return crate::error::LFS_ERR_CORRUPT;
}
if lfs_pair_cmp(&(*pdir).tail, pair) == 0 {
if !have_fetched {
let err = lfs_dir_fetch(lfs, pdir, &(*pdir).tail);
if err != 0 {
return crate::lfs_pass_err!(err);
}
if lfs_pair_isnull(&(*pdir).tail) {
return crate::error::LFS_ERR_NOENT;
}
}
return 0;
}
let err = lfs_dir_fetch(lfs, pdir, &(*pdir).tail);
if err != 0 {
return crate::lfs_pass_err!(err);
}
have_fetched = true;
}
crate::error::LFS_ERR_NOENT
}
}
#[repr(C)]
pub struct LfsFsParentMatch {
pub lfs: *mut crate::fs::Lfs,
pub pair: [crate::types::lfs_block_t; 2],
}
const LFS_CMP_EQ: i32 = 0;
const LFS_CMP_LT: i32 = 1;
pub unsafe extern "C" fn lfs_fs_parent_match(
data: *mut core::ffi::c_void,
_tag: crate::types::lfs_tag_t,
buffer: *const core::ffi::c_void,
) -> i32 {
use crate::bd::bd::lfs_bd_read;
use crate::tag::lfs_diskoff;
use crate::util::{lfs_pair_cmp, lfs_pair_fromle32};
if data.is_null() || buffer.is_null() {
return LFS_CMP_LT;
}
let find = &*(data as *const LfsFsParentMatch);
let disk = &*(buffer as *const lfs_diskoff);
let mut child: [crate::types::lfs_block_t; 2] = [0, 0];
let err = lfs_bd_read(
find.lfs,
core::ptr::null(),
&mut (*find.lfs).rcache,
(*find.lfs).cfg.as_ref().expect("cfg").block_size,
disk.block,
disk.off,
child.as_mut_ptr() as *mut u8,
8,
);
if err != 0 {
return crate::lfs_pass_err!(err);
}
lfs_pair_fromle32(&mut child);
if lfs_pair_cmp(&child, &find.pair) == 0 {
LFS_CMP_EQ
} else {
LFS_CMP_LT
}
}
pub fn lfs_fs_parent(
lfs: *mut crate::fs::Lfs,
pair: *const [crate::types::lfs_block_t; 2],
parent: *mut crate::dir::LfsMdir,
) -> crate::types::lfs_stag_t {
use crate::dir::fetch::lfs_dir_fetchmatch;
use crate::fs::mount::{lfs_tortoise_detectcycles, LfsTortoise};
use crate::lfs_type::lfs_type::LFS_TYPE_DIRSTRUCT;
use crate::tag::lfs_mktag;
use crate::types::{lfs_block_t, LFS_BLOCK_NULL};
use crate::util::lfs_pair_isnull;
unsafe {
(*parent).tail = [0, 1];
let mut tortoise = LfsTortoise {
pair: [LFS_BLOCK_NULL, LFS_BLOCK_NULL],
i: 1,
period: 1,
};
#[cfg(feature = "loop_limits")]
const MAX_PARENT_ITER: u32 = 2048;
#[cfg(feature = "loop_limits")]
let mut iter: u32 = 0;
while !lfs_pair_isnull(&(*parent).tail) {
#[cfg(feature = "loop_limits")]
{
if iter >= MAX_PARENT_ITER {
panic!(
"loop_limits: MAX_PARENT_ITER ({}) exceeded in lfs_fs_parent (parent)",
MAX_PARENT_ITER
);
}
iter += 1;
}
let err = lfs_tortoise_detectcycles(parent, &mut tortoise);
if err < 0 {
return crate::lfs_pass_err!(err);
}
let find_match = LfsFsParentMatch {
lfs,
pair: [(*pair)[0], (*pair)[1]],
};
let tag = lfs_dir_fetchmatch(
lfs as *mut _ as *const core::ffi::c_void,
parent,
&(*parent).tail as *const _,
lfs_mktag(0x7ff, 0, 0x3ff),
lfs_mktag(LFS_TYPE_DIRSTRUCT, 0, 8),
core::ptr::null_mut(),
Some(lfs_fs_parent_match),
&find_match as *const _ as *mut core::ffi::c_void,
);
if tag != 0 && tag != crate::error::LFS_ERR_NOENT {
return tag;
}
}
crate::error::LFS_ERR_NOENT
}
}