--- /dev/null
+#include <set>
+#include <map>
+#include <string>
+#include <iostream>
+#include <sys/stat.h>
+#include <boost/filesystem.hpp>
+#include <boost/algorithm/string/regex.hpp>
+#include <boost/regex.hpp>
+#include <boost/format.hpp>
+#include <boost/program_options.hpp>
+
+using namespace std;
+using namespace boost::filesystem;
+using namespace boost::algorithm;
+
+namespace po = boost::program_options;
+
+set<ino_t> inodes;
+map<path,long> dirs;
+
+boost::regex prefix_re;
+
+path strip_path( const path& dir ) {
+ return erase_regex_copy(dir.string(), prefix_re );
+}
+
+string ToHumanReadable(long x)
+{
+ //CONSTANTS FOR SIZING
+ double KB = 1024;
+ double MB = 1024 * KB;
+ double GB = 1024 * MB;
+
+ if (x < KB)
+ return (boost::format("%6d") % x).str();
+ else if (x < MB)
+ {
+ return (boost::format("%6.1fkB") % (x / KB)).str();
+ }
+ else if (x < GB)
+ {
+ return (boost::format("%6.1fMB") % (x / MB)).str();
+ }
+ else if (x >= GB)
+ {
+ return (boost::format("%6.1fGB") % (x / GB)).str();
+ }
+}
+
+
+void handle_file( const path& dir, const path& p ) {
+ struct stat buf;
+ if ( lstat(p.string().c_str(), &buf )) {
+ cout << "error" << endl;
+ } else {
+ // cout << "inode: " << buf.st_ino << "; size: " << buf.st_size << endl;
+ if (inodes.find( buf.st_ino ) == inodes.end() ) {
+ inodes.insert( buf.st_ino );
+ dirs[strip_path(dir)] += buf.st_size;
+ // cout << "New inode, size of " << strip_path(dir) << " is now " << dirs[strip_path(dir)] << endl;
+ } else {
+ // cout << "Old inode" << endl;
+ }
+ }
+}
+
+void handle_dir( const path& dir ) {
+ // cout << dir << endl;
+ if ( dirs.find(strip_path(dir)) == dirs.end() ) {
+ dirs[strip_path(dir)] = 0;
+ }
+ directory_iterator i(dir), dir_end;
+ for(;i!= dir_end; ++i) {
+ if ( is_directory( *i ) ) {
+ handle_dir( *i );
+ } else {
+ handle_file( dir, *i );
+ }
+ }
+}
+
+int main( int argc, char** argv ) {
+ string start_dir;
+ string prefix;
+ long size_limit;
+
+ // Declare the supported options.
+ po::options_description desc("Allowed options");
+ desc.add_options()
+ ("help", "produce help message")
+ ("start-dir,s", po::value<string>(&start_dir)->default_value("/var/lib/backuppc/pc/nogrod"), "Starting directory")
+ ("prefix,p", po::value<string>(&prefix)->default_value("/var/lib/backuppc/pc/nogrod/[0-9]*/(f%2f|f)"), "Prefix to remove for counting (regular expression)")
+ ("limit,l", po::value<long>(&size_limit)->default_value(1), "Minimal directory size to show")
+ ;
+
+ po::variables_map vm;
+ po::store(po::parse_command_line(argc, argv, desc), vm);
+ po::notify(vm);
+
+ if (vm.count("help")) {
+ cout << desc << "\n";
+ return 1;
+ }
+
+ prefix_re = boost::regex(prefix);
+
+ handle_dir( start_dir );
+
+
+ map<long,path> result;
+ for( map<path,long>::const_iterator i = dirs.begin(); i != dirs.end(); ++i ) {
+ if ( i->second >= size_limit ) result[i->second] = i->first;
+ }
+ for( map<long,path>::const_iterator i = result.begin(); i != result.end(); ++i ) {
+ cout << ToHumanReadable(i->first) << " (" << i->first << ") " << i->second << endl;
+ }
+}