From 7c4acf3241acf683408a34f63fd52f6d6f8a58df Mon Sep 17 00:00:00 2001 From: Kelvin Sherlock Date: Wed, 3 Aug 2016 20:10:22 -0400 Subject: [PATCH] dot_clean, like the OS X utility. --- dot_clean.cpp | 196 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 196 insertions(+) create mode 100644 dot_clean.cpp diff --git a/dot_clean.cpp b/dot_clean.cpp new file mode 100644 index 0000000..1c4ccf8 --- /dev/null +++ b/dot_clean.cpp @@ -0,0 +1,196 @@ + + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#include + +#include "applefile.h" +#include "mapped_file.h" + + +std::vector unlink_list; +std::vector rmdir_list; + + +bool _f = false; +bool _m = false; +bool _n = false; +bool _p = false; +bool _s = false; +bool _v = false; + +int _rv = 0; + + + + +void throw_damaged_file() { + throw std::runtime_error("File is damaged."); +} + +void throw_eof() { + throw std::runtime_error("Unexpected end of file."); +} + + +void throw_errno() { + throw std::system_error(errno, std::system_category()); +} + + +void throw_errno(const std::string &what) { + throw std::system_error(errno, std::system_category(), what); +} + + +class defer { +public: + typedef std::function FX; + defer() = default; + + defer(FX fx) : _fx(fx) {} + defer(const defer &) = delete; + defer(defer &&) = default; + defer & operator=(const defer &) = delete; + defer & operator=(defer &&) = default; + + void cancel() { _fx = nullptr; } + ~defer() { if (_fx) _fx(); } +private: + FX _fx; +}; + + + +void one_file(const std::string &data, const std::string &rsrc) noexcept try { + + if (_v) fprintf(stdout, "%s\n", data.c_str()); + + int fd = open(data.c_str(), O_RDONLY); + if (fd < 0) { + + if (errno == ENOENT && _n) { unlink_list.push_back(rsrc); return; } + throw_errno(); + } + + defer close_fd([fd]{close(fd); }); + + mapped_file mf(rsrc, mapped_file::priv); + + + if (!_p) unlink_list.push_back(rsrc); + +} catch (std::exception &ex) { + _rv = 1; + fprintf(stderr, "%s : %s\n", data.c_str(), ex.what()); +} + +void one_dir(std::string dir) noexcept { + + DIR *dirp; + dirent *dp; + + // check for .AppleDouble folder. + + + if (dir.empty()) return; + + while (!dir.empty() && dir.back() == '/') dir.pop_back(); + dir.push_back('/'); + + std::string ad = dir + ".AppleDouble/"; + + dirp = opendir(ad.c_str()); + if (dirp) { + while ( (dp = readdir(dirp)) ) { + + if (dp->d_name[0] == '.') continue; + + std::string name = dp->d_name; + + one_file(dir + name, ad + name); + } + if (!_p) rmdir_list.push_back(ad); // delete it if empty. + closedir(dirp); + } + + + dirp = opendir(dir.c_str()); + + while ( (dp = readdir(dirp)) ) { + if (dp->d_name[0] != '.') continue; + if (dp->d_name[1] != '_') continue; + + std::string name = dp->d_name; + one_file(dir + name.substr(2), dir + name); + } + closedir(dirp); + +} + +void usage() { + fputs("Usage: dot_clean [-fhmnpsv] directory ...\n", stderr); + exit(EX_USAGE); +} + +void help() { + fputs( + "Usage: dot_clean [-fhmnpsv] directory ...\n" + "\n" + " -f Disable recursion\n" + " -h Display help\n" + " -m Always delete apple double files\n" + " -n Deleted apple double files if there is no matching native file\n" + " -p Preserve apple double file.\n" + " -s Follow symbolic links.\n" + " -v Be verbose\n", + stdout); + + exit(EX_OK); +} + +int main(int argc, char **argv) { + + int c; + + while ((c = getopt(argc, argv, "fhmnpsv")) != -1) { + switch(c) { + case 'f': _f = true; break; + case 'h': help(); break; + case 'm': _m = true; break; + case 'n': _n = true; break; + case 'p': _p = true; break; + case 's': _s = true; break; + case 'v': _v = true; break; + case ':': + case '?': + default: + usage(); + break; + } + } + + argv += optind; + argc -= optind; + + if (!argc) usage(); + + for (int i = 0; i < argc; ++i) one_dir(argv[i]); + + return _rv; +} \ No newline at end of file