Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 52 additions & 27 deletions Fileinfo.cc
Original file line number Diff line number Diff line change
Expand Up @@ -166,11 +166,19 @@ Fileinfo::Fileinfostat::Fileinfostat()
int
Fileinfo::deletefile()
{
const int ret = unlink(name().c_str());
if (ret) {
std::cerr << "Failed deleting file " << name() << '\n';
std::vector<std::string> allfiles;
allfiles.push_back(m_filename);
allfiles.insert(allfiles.end(), m_aliases.begin(), m_aliases.end());

for (const std::string& n : allfiles) {
const int ret = unlink(n.c_str());

if (ret) {
std::cerr << "Failed deleting file " << n << '\n';
return ret;
}
}
return ret;
return 0;
}

namespace {
Expand Down Expand Up @@ -267,39 +275,56 @@ transactional_operation(const std::string& filename, const Func& f)
int
Fileinfo::makesymlink(const Fileinfo& A)
{
const int retval =
transactional_operation(name(), [&](const std::string& filename) {
// The tricky thing is that the path must be correct, as seen from
// the directory where *this is. Making the path absolute solves this
// problem. Doing string manipulations to find how to make the path
// relative is prone to error because directories can be symlinks.
std::string target = A.name();
makeAbsolute(target);
// clean up the path, so it does not contain sequences "/./" or "//"
simplifyPath(target);
return symlink(target.c_str(), filename.c_str());
});

if (retval) {
std::cerr << "Failed to make symlink " << name() << " to " << A.name()
<< '\n';
std::vector<std::string> allfiles;
allfiles.push_back(m_filename);
allfiles.insert(allfiles.end(), m_aliases.begin(), m_aliases.end());

// The tricky thing is that the path must be correct, as seen from
// the directory where *this is. Making the path absolute solves this
// problem. Doing string manipulations to find how to make the path
// relative is prone to error because directories can be symlinks.
std::string target = A.name();
makeAbsolute(target);
// clean up the path, so it does not contain sequences "/./" or "//"
simplifyPath(target);

for (const std::string& n : allfiles) {
const int retval =
transactional_operation(n, [&target](const std::string& filename) {
return symlink(target.c_str(), filename.c_str());
});

if (retval) {
std::cerr << "Failed to make symlink " << n << " to " << A.name()
<< '\n';
return retval;
}
}
return retval;
return 0;
}

// makes a hard link that points to A
int
Fileinfo::makehardlink(const Fileinfo& A)
{
return transactional_operation(name(), [&](const std::string& filename) {
// make a hardlink.
const int retval = link(A.name().c_str(), filename.c_str());
std::vector<std::string> allfiles;
allfiles.push_back(m_filename);
allfiles.insert(allfiles.end(), m_aliases.begin(), m_aliases.end());

for (const std::string& n : allfiles) {
const int retval =
transactional_operation(n, [&A](const std::string& filename) {
// make a hardlink.
return link(A.name().c_str(), filename.c_str());
});

if (retval) {
std::cerr << "Failed to make hardlink " << filename << " to " << A.name()
std::cerr << "Failed to make hardlink " << n << " to " << A.name()
<< '\n';
return retval;
}
return retval;
});
}
return 0;
}

int
Expand Down
10 changes: 10 additions & 0 deletions Fileinfo.hh
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <array>
#include <cstdint>
#include <string>
#include <vector>

// os specific headers
#include <sys/types.h> //for off_t and others.
Expand Down Expand Up @@ -127,6 +128,12 @@ public:
// gets the filename
const std::string& name() const { return m_filename; }

// gets the filename
const std::vector<std::string>& aliases() const { return m_aliases; }

// adds a filename alias
void add_alias(std::string n) { m_aliases.push_back(n); }

// gets the command line index this item was found at
int get_cmdline_index() const { return m_cmdline_index; }

Expand Down Expand Up @@ -174,6 +181,9 @@ private:
// to be deleted or not
bool m_delete;

// list of hardlinks
std::vector<std::string> m_aliases;

duptype m_duptype;

// If two files are found to be identical, the one with highest ranking is
Expand Down
15 changes: 10 additions & 5 deletions Rdutil.cc
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,19 @@ Rdutil::printtofile(const std::string& filename) const
// This uses "priority" instead of "cmdlineindex". Change this the day
// a change in output format is allowed (for backwards compatibility).
output << "# Automatically generated\n";
output << "# duptype id depth size device inode priority name\n";
output << "# duptype id depth size device inode priority name(s)\n";

std::vector<Fileinfo>::iterator it;
for (it = m_list.begin(); it != m_list.end(); ++it) {
output << Fileinfo::getduptypestring(*it) << " " << it->getidentity() << " "
<< it->depth() << " " << it->size() << " " << it->device() << " "
<< it->inode() << " " << it->get_cmdline_index() << " " << it->name()
<< '\n';
<< it->inode() << " " << it->get_cmdline_index() << " " << it->name();
if (!it->aliases().empty()) {
output << " aliases:";
for (const std::string& n : it->aliases())
output << " " << n;
}
output << '\n';
}
output << "# end of file\n";
f1.close();
Expand Down Expand Up @@ -313,9 +318,9 @@ Rdutil::removeIdenticalInodes()
// let the highest-ranking element not be deleted. do this in order, to be
// cache friendly.
auto best = std::min_element(first, last, cmpRank);
std::for_each(first, best, [](Fileinfo& f) { f.setdeleteflag(true); });
std::for_each(first, last, [](Fileinfo& f) { f.setdeleteflag(true); });
best->setdeleteflag(false);
std::for_each(best + 1, last, [](Fileinfo& f) { f.setdeleteflag(true); });
std::for_each(first, last, [&best](Fileinfo& f) { if (f.deleteflag()) best->add_alias(f.name()); });
});
return cleanup();
}
Expand Down