Hi Javier, 2009/7/31 Javier Fernández-Sanguino Peña <j...@computer.org>: > > tags 284274 patch > thanks > > Attached is a patch to the program sources (through the use of a dpatch patch > in the Debian package) that adds a new -L / --linkhard option to fdupes. This > option will replace all duplicate files with hardlinks which is useful in > order to reduce space.
Thanks for the patch! > It has been tested only slightly, but the code looks (to me) about right. > > Please consider this patch and include it in the Debian package. I've added upstream in the loop, so he can comment. Hi Adrian, a fellow Debian Developer sent me a patch on fdupes to replace duplicate files with hardlink. It would be nice if you can merge it fdupe original source code. Cheers, -- Sandro Tosi (aka morph, morpheus, matrixhasu) My website: http://matrixhasu.altervista.org/ Me at Debian: http://wiki.debian.org/SandroTosi
diff -Nru fdupes-1.50-PR2/debian/changelog fdupes-1.50-PR2-2/debian/changelog --- fdupes-1.50-PR2/debian/changelog 2009-07-31 00:47:23.000000000 +0200 +++ fdupes-1.50-PR2-2/debian/changelog 2009-07-31 00:44:27.000000000 +0200 @@ -1,3 +1,11 @@ +fdupes (1.50-PR2-2.1) unstable; urgency=low + + * debian/patches/50_bts284274_hardlinkreplace.dpatch created. + - added -L / --linkhard to make fdupes replace files with hardlinks. Also + update the manual page; Closes: 284274 + + -- Javier Fernandez-Sanguino Pen~a <j...@debian.org> Fri, 31 Jul 2009 00:43:11 +0200 + fdupes (1.50-PR2-2) unstable; urgency=low * debian/control diff -Nru fdupes-1.50-PR2/debian/patches/00list fdupes-1.50-PR2-2/debian/patches/00list --- fdupes-1.50-PR2/debian/patches/00list 2009-07-31 00:47:23.000000000 +0200 +++ fdupes-1.50-PR2-2/debian/patches/00list 2009-07-31 00:43:02.000000000 +0200 @@ -5,3 +5,4 @@ 20_bts447601_lfs_support 30_bts481809_manpage_summarize 40_bts511702_nohidden_support +50_bts284274_hardlinkreplace diff -Nru fdupes-1.50-PR2/debian/patches/50_bts284274_hardlinkreplace.dpatch fdupes-1.50-PR2-2/debian/patches/50_bts284274_hardlinkreplace.dpatch --- fdupes-1.50-PR2/debian/patches/50_bts284274_hardlinkreplace.dpatch 1970-01-01 01:00:00.000000000 +0100 +++ fdupes-1.50-PR2-2/debian/patches/50_bts284274_hardlinkreplace.dpatch 2009-07-31 00:42:42.000000000 +0200 @@ -0,0 +1,228 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 50_bts284274_hardlinkreplace.dpatch by <j...@debian.org> +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: No description. + +...@dpatch@ +diff -urNad fdupes-1.50-PR2~/fdupes.1 fdupes-1.50-PR2/fdupes.1 +--- fdupes-1.50-PR2~/fdupes.1 2009-07-31 00:38:28.000000000 +0200 ++++ fdupes-1.50-PR2/fdupes.1 2009-07-31 00:42:14.000000000 +0200 +@@ -58,10 +58,17 @@ + .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 -v --version + display fdupes version + .TP +diff -urNad fdupes-1.50-PR2~/fdupes.c fdupes-1.50-PR2/fdupes.c +--- fdupes-1.50-PR2~/fdupes.c 2009-07-31 00:38:28.000000000 +0200 ++++ fdupes-1.50-PR2/fdupes.c 2009-07-31 00:41:08.000000000 +0200 +@@ -53,6 +53,8 @@ + #define F_NOPROMPT 0x0400 + #define F_SUMMARIZEMATCHES 0x0800 + #define F_EXCLUDEHIDDEN 0x1000 ++#define F_HARDLINKFILES 0x2000 ++#define F_DEBUGINFO 0x4000 + + char *program_name; + +@@ -881,6 +883,88 @@ + 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) +@@ -971,10 +1055,14 @@ + 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(" -r --dlink \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(" \teach set of duplicates without prompting the user\n"); + printf(" -v --version \tdisplay fdupes version\n"); + printf(" -h --help \tdisplay this help message\n\n"); + #ifdef OMIT_GETOPT_LONG +@@ -1010,12 +1098,14 @@ + { "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' }, + { 0, 0, 0, 0 } +@@ -1029,7 +1119,7 @@ + + oldargv = cloneargs(argc, argv); + +- while ((opt = GETOPT(argc, argv, "frRq1Ss::HlnAdvhNm" ++ while ((opt = GETOPT(argc, argv, "frRq1Ss::HlLnAdDvhNm" + #ifndef OMIT_GETOPT_LONG + , long_options, NULL + #endif +@@ -1068,6 +1158,12 @@ + 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); +@@ -1102,6 +1198,16 @@ + 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); + +@@ -1187,12 +1293,23 @@ + + else + +- if (ISFLAG(flags, F_SUMMARIZEMATCHES)) +- summarizematches(files); +- +- else ++ if (ISFLAG(flags, F_HARDLINKFILES)) + +- printmatches(files); ++ if (ISFLAG(flags, F_DEBUGINFO)) ++ hardlinkfiles(files, 1); ++ else ++ hardlinkfiles(files, 0); ++ ++ else { ++ ++ if (ISFLAG(flags, F_SUMMARIZEMATCHES)) ++ summarizematches(files); ++ ++ else ++ ++ printmatches(files); ++ ++ } + + while (files) { + curfile = files->next;