Skip to content

Commit

Permalink
counts hard links only once for each dir
Browse files Browse the repository at this point in the history
  • Loading branch information
wookietreiber committed Aug 20, 2024
1 parent 23b3ebd commit dd82293
Show file tree
Hide file tree
Showing 4 changed files with 223 additions and 53 deletions.
12 changes: 12 additions & 0 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,17 @@ pub fn build() -> Command {
)
.value_parser(value_parser!(usize));

let count_links = Arg::new("count-links")
.short('l')
.long("count-links")
.action(ArgAction::SetTrue)
.hide_short_help(true)
.long_help(
"Count sizes many times if hard linked. The default behavior is to count each \
hard linked object only once for each point of interest, i.e. once for every \
DIR and once for every sub-directory if max depth is used."
);

let kb_allocated = Arg::new("kb-allocated")
.long("kb-allocated")
.action(ArgAction::SetTrue)
Expand Down Expand Up @@ -95,6 +106,7 @@ pub fn build() -> Command {
.args(filter())
.args(mmapplypolicy())
.arg(max_depth)
.arg(count_links)
.arg(kb_allocated)
.arg(debug)
.arg(help)
Expand Down
4 changes: 4 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ pub struct Config {
pub dirs: Option<Vec<PathBuf>>,
pub debug: bool,
pub filter: Filter,
pub count_links: bool,
pub max_depth: Option<usize>,
pub mm_nodes: Option<String>,
pub mm_local_work_dir: Option<PathBuf>,
Expand All @@ -60,6 +61,8 @@ impl TryFrom<ArgMatches> for Config {

let filter = Filter::try_from(&args)?;

let count_links = args.get_flag("count-links");

let max_depth = args
.get_one::<usize>("max-depth")
.copied()
Expand All @@ -85,6 +88,7 @@ impl TryFrom<ArgMatches> for Config {
dirs,
debug,
filter,
count_links,
max_depth,
mm_nodes,
mm_local_work_dir,
Expand Down
67 changes: 64 additions & 3 deletions src/policy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ use std::fs::File;
use std::io::{self, Write};
use std::path::Path;

use anyhow::{anyhow, Context, Result};
use bstr::ByteSlice;
use libc::{gid_t, uid_t};

use crate::config::{Config, Filter};
Expand Down Expand Up @@ -56,7 +58,7 @@ fn policy_group(group: gid_t, attribute: &str) -> String {
RULE 'TOTAL'
LIST 'size'
DIRECTORIES_PLUS
SHOW(VARCHAR({attribute}))
SHOW(VARCHAR({attribute}) || ' ' || VARCHAR(NLINK))
WHERE GROUP_ID = {group}
"
)
Expand All @@ -71,7 +73,7 @@ fn policy_user(user: uid_t, attribute: &str) -> String {
RULE 'TOTAL'
LIST 'size'
DIRECTORIES_PLUS
SHOW(VARCHAR({attribute}))
SHOW(VARCHAR({attribute}) || ' ' || VARCHAR(NLINK))
WHERE USER_ID = {user}
"
)
Expand All @@ -86,7 +88,66 @@ fn policy_default(attribute: &str) -> String {
RULE 'TOTAL'
LIST 'size'
DIRECTORIES_PLUS
SHOW(VARCHAR({attribute}))
SHOW(VARCHAR({attribute}) || ' ' || VARCHAR(NLINK))
"
)
}

// inode generation snapid X Y Z -- path
pub struct Entry<'a>(Vec<&'a [u8]>, &'a [u8]);

impl Entry<'_> {
const INVALID: &'static str = "invalid line in policy report";

pub fn inode_str(&self) -> Result<&str> {
self.0[0]
.to_str()
.context("reading inode field from policy report")
}

pub fn bytes_str(&self) -> Result<&str> {
self.0[4]
.to_str()
.context("reading bytes field from policy report")
}

pub fn bytes(&self) -> Result<u64> {
self.bytes_str().and_then(|s| {
s.parse::<u64>()
.context("parsing bytes field from policy report")
})
}

pub fn nlink_str(&self) -> Result<&str> {
self.0[5]
.to_str()
.context("reading number of links field from policy report")
}

pub fn path(&self) -> Result<&Path> {
self.1
.to_path()
.context("parsing path field from policy report")
}
}

impl<'a> TryFrom<&'a Vec<u8>> for Entry<'a> {
type Error = anyhow::Error;

fn try_from(line: &'a Vec<u8>) -> Result<Self> {
let groups = line.split_str(" -- ").collect::<Vec<_>>();

if groups.len() != 2 {
return Err(anyhow!(Entry::INVALID));
}

let fields = groups[0].splitn_str(7, " ").take(6).collect::<Vec<_>>();
let path = groups[1];

if fields.len() == 6 {
Ok(Self(fields, path))
} else {
Err(anyhow!(Entry::INVALID))
}
}
}
Loading

0 comments on commit dd82293

Please sign in to comment.