diff --git a/50_bts284274_hardlinkreplace.dpatch b/50_bts284274_hardlinkreplace.dpatch new file mode 100644 index 0000000..b60b8a4 --- /dev/null +++ b/50_bts284274_hardlinkreplace.dpatch @@ -0,0 +1,228 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 50_bts284274_hardlinkreplace.dpatch by +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: Replace duplicate files with hardlinks + +@DPATCH@ +Index: fdupes-1.50-PR2/fdupes.c +=================================================================== +--- fdupes-1.50-PR2.orig/fdupes.c ++++ fdupes-1.50-PR2/fdupes.c +@@ -54,6 +54,8 @@ + #define F_SUMMARIZEMATCHES 0x0800 + #define F_EXCLUDEHIDDEN 0x1000 + #define F_PERMISSIONS 0x2000 ++#define F_HARDLINKFILES 0x4000 ++#define F_DEBUGINFO 0x8000 + + typedef enum { + ORDER_TIME = 0, +@@ -904,6 +906,88 @@ void deletefiles(file_t *files, int prom + free(preservestr); + } + ++void hardlinkfiles(file_t *files, int debug) ++{ ++ int counter; ++ int groups = 0; ++ int curgroup = 0; ++ file_t *tmpfile; ++ file_t *curfile; ++ file_t **dupelist; ++ int max = 0; ++ int x = 0; ++ ++ curfile = files; ++ ++ while (curfile) { ++ if (curfile->hasdupes) { ++ counter = 1; ++ groups++; ++ ++ tmpfile = curfile->duplicates; ++ while (tmpfile) { ++ counter++; ++ tmpfile = tmpfile->duplicates; ++ } ++ ++ if (counter > max) max = counter; ++ } ++ ++ curfile = curfile->next; ++ } ++ ++ max++; ++ ++ dupelist = (file_t**) malloc(sizeof(file_t*) * max); ++ ++ if (!dupelist) { ++ errormsg("out of memory\n"); ++ exit(1); ++ } ++ ++ while (files) { ++ if (files->hasdupes) { ++ curgroup++; ++ counter = 1; ++ dupelist[counter] = files; ++ ++ if (debug) printf("[%d] %s\n", counter, files->d_name); ++ ++ tmpfile = files->duplicates; ++ ++ while (tmpfile) { ++ dupelist[++counter] = tmpfile; ++ if (debug) printf("[%d] %s\n", counter, tmpfile->d_name); ++ tmpfile = tmpfile->duplicates; ++ } ++ ++ if (debug) printf("\n"); ++ ++ /* preserve only the first file */ ++ ++ printf(" [+] %s\n", dupelist[1]->d_name); ++ for (x = 2; x <= counter; x++) { ++ if (unlink(dupelist[x]->d_name) == 0) { ++ if ( link(dupelist[1]->d_name, dupelist[x]->d_name) == 0 ) { ++ printf(" [h] %s\n", dupelist[x]->d_name); ++ } else { ++ printf("-- unable to create a hardlink for the file: %s\n", strerror(errno)); ++ printf(" [!] %s ", dupelist[x]->d_name); ++ } ++ } else { ++ printf(" [!] %s ", dupelist[x]->d_name); ++ printf("-- unable to delete the file!\n"); ++ } ++ } ++ printf("\n"); ++ } ++ ++ files = files->next; ++ } ++ ++ free(dupelist); ++} ++ + int sort_pairs_by_arrival(file_t *f1, file_t *f2) + { + if (f2->duplicates != 0) +@@ -1000,10 +1084,12 @@ void help_text() + printf(" \twith -s or --symlinks, or when specifying a\n"); + printf(" \tparticular directory more than once; refer to the\n"); + printf(" \tfdupes documentation for additional information\n"); +- //printf(" -l --relink \t(description)\n"); ++ printf(" -L --linkhard \thardlink duplicate files to the first file in\n"); ++ printf(" \teach set of duplicates without prompting the user\n"); + printf(" -N --noprompt \ttogether with --delete, preserve the first file in\n"); + printf(" \teach set of duplicates and delete the rest without\n"); + printf(" \twithout prompting the user\n"); ++ printf(" -D --debug \tenable debugging information\n"); + printf(" -p --permissions \tdon't consider files with different owner/group or permission bits as duplicates\n"); + printf(" -o --order \tselect sort order for output, linking and deleting. One of:\n"); + printf(" time \torder by mtime (default)\n"); +@@ -1044,12 +1130,14 @@ int main(int argc, char **argv) { + { "symlinks", 0, 0, 's' }, + { "hardlinks", 0, 0, 'H' }, + { "relink", 0, 0, 'l' }, ++ { "linkhard", 0, 0, 'L' }, + { "noempty", 0, 0, 'n' }, + { "nohidden", 0, 0, 'A' }, + { "delete", 0, 0, 'd' }, + { "version", 0, 0, 'v' }, + { "help", 0, 0, 'h' }, + { "noprompt", 0, 0, 'N' }, ++ { "debug", 0, 0, 'D' }, + { "summarize", 0, 0, 'm'}, + { "summary", 0, 0, 'm' }, + { "permissions", 0, 0, 'p' }, +@@ -1065,7 +1153,7 @@ int main(int argc, char **argv) { + + oldargv = cloneargs(argc, argv); + +- while ((opt = GETOPT(argc, argv, "frRq1SsHlndvhNmpo:" ++ while ((opt = GETOPT(argc, argv, "frRq1SsHlLndDvhNmpo:" + #ifndef OMIT_GETOPT_LONG + , long_options, NULL + #endif +@@ -1104,6 +1192,12 @@ int main(int argc, char **argv) { + case 'd': + SETFLAG(flags, F_DELETEFILES); + break; ++ case 'L': ++ SETFLAG(flags, F_HARDLINKFILES); ++ break; ++ case 'D': ++ SETFLAG(flags, F_DEBUGINFO); ++ break; + case 'v': + printf("fdupes %s\n", VERSION); + exit(0); +@@ -1151,6 +1245,16 @@ int main(int argc, char **argv) { + exit(1); + } + ++ if (ISFLAG(flags, F_HARDLINKFILES) && ISFLAG(flags, F_DELETEFILES)) { ++ errormsg("options --linkhard and --delete are not compatible\n"); ++ exit(1); ++ } ++ ++ if (ISFLAG(flags, F_HARDLINKFILES) && ISFLAG(flags, F_CONSIDERHARDLINKS)) { ++ errormsg("options --linkhard and --hardlinks are not compatible\n"); ++ exit(1); ++ } ++ + if (ISFLAG(flags, F_RECURSEAFTER)) { + firstrecurse = nonoptafter("--recurse:", argc, oldargv, argv, optind); + +@@ -1237,12 +1341,23 @@ int main(int argc, char **argv) { + + else + +- if (ISFLAG(flags, F_SUMMARIZEMATCHES)) +- summarizematches(files); +- +- else ++ if (ISFLAG(flags, F_HARDLINKFILES)) ++ ++ if (ISFLAG(flags, F_DEBUGINFO)) ++ hardlinkfiles(files, 1); ++ else ++ hardlinkfiles(files, 0); + +- printmatches(files); ++ else { ++ ++ if (ISFLAG(flags, F_SUMMARIZEMATCHES)) ++ summarizematches(files); ++ ++ else ++ ++ printmatches(files); ++ ++ } + + while (files) { + curfile = files->next; +Index: fdupes-1.50-PR2/fdupes.1 +=================================================================== +--- fdupes-1.50-PR2.orig/fdupes.1 ++++ fdupes-1.50-PR2/fdupes.1 +@@ -59,10 +59,17 @@ prompt user for files to preserve, delet + .B CAVEATS + below) + .TP ++.B -L --hardlink ++replace all duplicate files with hardlinks to the ++first file in each set of duplicates ++.TP + .B -N --noprompt + when used together with \-\-delete, preserve the first file in each + set of duplicates and delete the others without prompting the user + .TP ++.B -D --debug ++provide debugging information ++.TP + .B -p --permissions + don't consider files with different owner/group or permission bits as duplicates + .TP diff --git a/fdupes.changes b/fdupes.changes index 1b3851d..60c0db4 100644 --- a/fdupes.changes +++ b/fdupes.changes @@ -1,3 +1,9 @@ +------------------------------------------------------------------- +Sun Dec 21 19:58:41 UTC 2014 - bwiedemann@suse.com + +- add -L (--linkhard) option + add 50_bts284274_hardlinkreplace.dpatch + ------------------------------------------------------------------- Tue Apr 29 16:08:34 UTC 2014 - stefan.bruens@rwth-aachen.de diff --git a/fdupes.spec b/fdupes.spec index ead3427..0548df1 100644 --- a/fdupes.spec +++ b/fdupes.spec @@ -51,6 +51,8 @@ Patch9: 0009-glibc-endianness-check-in-md5.patch Patch10: 0010-add-permissions-mode.patch #PATCH-FIX-OPENSUSE: -o/--order mode Patch11: 0011-add-an-option-to-sort-duplicate-files-by-name.patch +#PATCH-FIX-DEBIAN: add -L/--linkhard +Patch20: 50_bts284274_hardlinkreplace.dpatch BuildRoot: %{_tmppath}/%{name}-%{version}-build %if 0%{?centos_version} || 0%{?rhel_version} || 0%{?fedora_version} @@ -76,6 +78,7 @@ residing within specified directories %patch9 -p1 %patch10 -p1 %patch11 -p1 +%patch20 -p1 %build echo -e "#!/bin/bash\n`which %__cc` \"\$@\"" >gcc