use crate::dir::commit::lfs_dir_commit;
use crate::dir::fetch::lfs_dir_fetch;
use crate::dir::find::lfs_dir_find;
use crate::dir::traverse::lfs_dir_get;
use crate::dir::LfsMdir;
use crate::error::{LFS_ERR_INVAL, LFS_ERR_NOATTR, LFS_ERR_NOENT, LFS_ERR_NOSPC};
use crate::fs::Lfs;
use crate::lfs_type::lfs_type::LFS_TYPE_USERATTR;
use crate::tag::{lfs_mattr, lfs_mktag, lfs_tag_id, lfs_tag_size};
use crate::types::{lfs_size_t, lfs_ssize_t};
use crate::util::lfs_min;
pub fn lfs_getattr_(
lfs: *mut Lfs,
path: *const u8,
r#type: u8,
buffer: *mut core::ffi::c_void,
size: lfs_size_t,
) -> lfs_ssize_t {
if lfs.is_null() || path.is_null() {
return crate::lfs_err!(LFS_ERR_INVAL);
}
unsafe {
let mut cwd = LfsMdir {
pair: [0, 0],
rev: 0,
off: 0,
etag: 0,
count: 0,
erased: false,
split: false,
tail: [(*lfs).root[0], (*lfs).root[1]],
};
let mut path_ptr = path;
let mut tag = lfs_dir_find(lfs, &mut cwd, &mut path_ptr, core::ptr::null_mut());
if tag < 0 {
return tag;
}
let mut id = lfs_tag_id(tag as u32) as u16;
if id == 0x3ff {
id = 0;
let err = lfs_dir_fetch(lfs, &mut cwd, &(*lfs).root);
if err != 0 {
return crate::lfs_pass_err!(err);
}
}
let gtag = lfs_mktag(
LFS_TYPE_USERATTR + r#type as u32,
id as u32,
lfs_min(size, (*lfs).attr_max),
);
tag = lfs_dir_get(lfs, &cwd, lfs_mktag(0x7ff, 0x3ff, 0), gtag, buffer);
if tag < 0 {
if tag == LFS_ERR_NOENT {
return crate::lfs_err!(LFS_ERR_NOATTR);
}
return tag;
}
lfs_tag_size(tag as u32) as lfs_ssize_t
}
}
pub fn lfs_commitattr(
lfs: *mut Lfs,
path: *const u8,
r#type: u8,
buffer: *const core::ffi::c_void,
size: lfs_size_t,
) -> i32 {
if lfs.is_null() || path.is_null() {
return crate::lfs_err!(LFS_ERR_INVAL);
}
unsafe {
let mut cwd = LfsMdir {
pair: [0, 0],
rev: 0,
off: 0,
etag: 0,
count: 0,
erased: false,
split: false,
tail: [(*lfs).root[0], (*lfs).root[1]],
};
let mut path_ptr = path;
let tag = lfs_dir_find(lfs, &mut cwd, &mut path_ptr, core::ptr::null_mut());
if tag < 0 {
return tag;
}
let mut id = lfs_tag_id(tag as u32) as u16;
if id == 0x3ff {
id = 0;
let err = lfs_dir_fetch(lfs, &mut cwd, &(*lfs).root);
if err != 0 {
return crate::lfs_pass_err!(err);
}
}
let attrs = [lfs_mattr {
tag: lfs_mktag(LFS_TYPE_USERATTR + r#type as u32, id as u32, size),
buffer,
}];
lfs_dir_commit(lfs, &mut cwd, attrs.as_ptr() as *const _, 1)
}
}
pub fn lfs_setattr_(
lfs: *mut Lfs,
path: *const u8,
r#type: u8,
buffer: *const core::ffi::c_void,
size: lfs_size_t,
) -> i32 {
if lfs.is_null() {
return crate::lfs_err!(LFS_ERR_INVAL);
}
unsafe {
if size > (*lfs).attr_max {
return crate::lfs_err!(LFS_ERR_NOSPC);
}
lfs_commitattr(lfs, path, r#type, buffer, size)
}
}
pub fn lfs_removeattr_(lfs: *mut Lfs, path: *const u8, r#type: u8) -> i32 {
lfs_commitattr(lfs, path, r#type, core::ptr::null(), 0x3ff)
}