return free_bytes;
}
+/**
+ * like du(1): return the number bytes used by a directory structure
+ * @param path File or directory to start counting recursively
+ * @param error Will contain the error if the return value is -1 [optional]
+ * @return size in bytes on success, -1 on error
+ *
+ * @attention This function does currently not consider that hardlinked files need
+ * space on disk only once. But this may be added later if needed. So make
+ * sure that calling functions don't depend on either behavior!
+ */
+long long du(const std::string &path, std::string *error)
+{
+ long long sum = 0;
+
+ try
+ {
+ Stat sp(path, false); // don't dereference symlinks here
+ if (!sp)
+ throw runtime_error("can't stat " + path);
+
+ // always add the space used, even if we have a directory, symlink or whatever:
+ // they need space on disk too
+
+ sum+=sp.bytes_on_disk();
+
+ if (sp.is_directory())
+ {
+ std::vector<std::string> dirents = get_dir(path, false);
+ BOOST_FOREACH(const std::string &filename, dirents)
+ {
+ // Delete subdir or file.
+ long long rtn = du(path + "/" + filename, error);
+ if (rtn == -1)
+ return -1;
+ sum+=rtn;
+ }
+ }
+ }
+ catch (exception &e)
+ {
+ if (error)
+ {
+ ostringstream out;
+ out << e.what() << " (" << strerror(errno) << ")";
+ *error = out.str();
+ }
+ return -1;
+ }
+ catch (...)
+ {
+ if (error)
+ {
+ ostringstream out;
+ out << "unknown error (" << strerror(errno) << ")";
+ *error = out.str();
+ }
+ return -1;
+ }
+
+ return sum;
+} // eo du
+
} // eo namespace I2n
mode_t umask(mode_t mask);
long long get_free_diskspace(const std::string& path);
-
+long long du(const std::string &path, std::string *error=NULL);
/*
** more specialized tool function(s)
BOOST_CHECK_EQUAL( -1, get_free_diskspace("/this/path/is/really/bogus") );
}
+BOOST_AUTO_TEST_CASE(TestDu)
+{
+ // Create unique directory
+ string unique_dir = I2n::mkdtemp("foobar.XXXXXX");
+ BOOST_REQUIRE(unique_dir.size() > 0);
+
+ // Test if it's really a directory
+ BOOST_CHECK_EQUAL(true, Stat(unique_dir).is_directory());
+
+ // Create dirs and files below it
+ const std::string sub_dir = unique_dir + "/" + "some_subdir";
+ const std::string some_file = sub_dir + "/" + "some_file";
+ BOOST_CHECK_EQUAL(true, I2n::mkdir(sub_dir));
+ BOOST_CHECK_EQUAL(true, write_file(some_file, "foobar and some more data, even more that Tom would like to see in one line without linebreak but I still want to have it all here"));
+
+ inpipestream cmd_du(string("du --block-size=1 --sum ")+unique_dir+" | cut -f 1");
+ string dustr;
+ if (cmd_du)
+ getline(cmd_du, dustr);
+
+ BOOST_CHECK_EQUAL( string_to<long long>(dustr), du(unique_dir) );
+
+ // Unlink it
+ BOOST_CHECK_EQUAL(true, I2n::recursive_delete(unique_dir));
+ BOOST_CHECK_EQUAL(false, Stat(unique_dir).is_directory());
+}
+
+
+
BOOST_AUTO_TEST_SUITE_END()