Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add --xdev option. Fixes #42 #92

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
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
2 changes: 2 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ who contributed the patch or idea appears first, followed by
those who've otherwise worked on that item. For a list of
contributors names and identifiers please see the CONTRIBUTORS file.

- Add --xdev option. [BD]

Changes from 1.6.0 to 1.6.1:

- Fix 'invalid option' error for -I. [AL]
Expand Down
3 changes: 2 additions & 1 deletion CONTRIBUTORS
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@ on their contributions. Names are listed in alphabetical order.
[SB] Stefan Brüns <[email protected]>
[ST] Sandro Tosi <[email protected]>
[ID] Ivan Diorditsa <[email protected]>
[TH] Tom Hoover <[email protected]>
[TH] Tom Hoover <[email protected]>
[BD] Bruce Duncan <[email protected]>
1 change: 1 addition & 0 deletions README
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Usage: fdupes [options] DIRECTORY...
-n --noempty exclude zero-length files from consideration
-A --nohidden exclude hidden files from consideration
-f --omitfirst omit the first file in each set of matches
-x --xdev skip directories on different filesystems
-1 --sameline list each set of matches on a single line
-S --size show size of duplicate files
-m --summarize summarize dupe information
Expand Down
3 changes: 3 additions & 0 deletions fdupes.1
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ omit the first file in each set of matches
.B -A --nohidden
exclude hidden files from consideration
.TP
.B -x --xdev
skip direcories on different filesystems

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be "directories".

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not that it makes a difference, since this project seems pretty dead 😞

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, good catch. Yes it's disappointing, but jdupes seems to fill the gap.

.TP
.B -1 --sameline
list each set of matches on a single line
.TP
Expand Down
61 changes: 50 additions & 11 deletions fdupes.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
#define F_PERMISSIONS 0x2000
#define F_REVERSE 0x4000
#define F_IMMEDIATE 0x8000
#define F_XDEV 0x10000

typedef enum {
ORDER_MTIME = 0,
Expand Down Expand Up @@ -250,7 +251,15 @@ int nonoptafter(char *option, int argc, char **oldargv,
return x;
}

int grokdir(char *dir, file_t **filelistp)
int samedev(dev_t dev, dev_t *rootdevs)
{
while (*rootdevs)
if (dev == *rootdevs++)
return 1;
return 0;
}

int grokdir(char *dir, file_t **filelistp, dev_t *rootdevs)
{
DIR *cd;
file_t *newfile;
Expand Down Expand Up @@ -337,8 +346,8 @@ int grokdir(char *dir, file_t **filelistp)
}

if (S_ISDIR(info.st_mode)) {
if (ISFLAG(flags, F_RECURSE) && (ISFLAG(flags, F_FOLLOWLINKS) || !S_ISLNK(linfo.st_mode)))
filecount += grokdir(newfile->d_name, filelistp);
if (ISFLAG(flags, F_RECURSE) && (ISFLAG(flags, F_FOLLOWLINKS) || !S_ISLNK(linfo.st_mode)) && (!ISFLAG(flags, F_XDEV) || samedev(info.st_dev, rootdevs)))
filecount += grokdir(newfile->d_name, filelistp, rootdevs);
free(newfile->d_name);
free(newfile);
} else {
Expand Down Expand Up @@ -1041,6 +1050,7 @@ void help_text()
printf(" -n --noempty \texclude zero-length files from consideration\n");
printf(" -A --nohidden \texclude hidden files from consideration\n");
printf(" -f --omitfirst \tomit the first file in each set of matches\n");
printf(" -x --xdev \tskip directories on different filesystems\n");
printf(" -1 --sameline \tlist each set of matches on a single line\n");
printf(" -S --size \tshow size of duplicate files\n");
printf(" -m --summarize \tsummarize dupe information\n");
Expand Down Expand Up @@ -1071,7 +1081,7 @@ void help_text()
}

int main(int argc, char **argv) {
int x;
int x, r;
int opt;
FILE *file1;
FILE *file2;
Expand All @@ -1083,6 +1093,7 @@ int main(int argc, char **argv) {
int progress = 0;
char **oldargv;
int firstrecurse;
dev_t *rootdevs = NULL;

#ifndef OMIT_GETOPT_LONG
static struct option long_options[] =
Expand Down Expand Up @@ -1110,6 +1121,7 @@ int main(int argc, char **argv) {
{ "permissions", 0, 0, 'p' },
{ "order", 1, 0, 'o' },
{ "reverse", 0, 0, 'i' },
{ "xdev", 0, 0, 'x' },
{ 0, 0, 0, 0 }
};
#define GETOPT getopt_long
Expand All @@ -1121,7 +1133,7 @@ int main(int argc, char **argv) {

oldargv = cloneargs(argc, argv);

while ((opt = GETOPT(argc, argv, "frRq1SsHlnAdvhNImpo:i"
while ((opt = GETOPT(argc, argv, "frRq1SsHlnAdvhNImpo:ix"
#ifndef OMIT_GETOPT_LONG
, long_options, NULL
#endif
Expand Down Expand Up @@ -1193,6 +1205,9 @@ int main(int argc, char **argv) {
case 'i':
SETFLAG(flags, F_REVERSE);
break;
case 'x':
SETFLAG(flags, F_XDEV);
break;

default:
fprintf(stderr, "Try `fdupes --help' for more information.\n");
Expand All @@ -1215,6 +1230,10 @@ int main(int argc, char **argv) {
exit(1);
}

if (ISFLAG(flags, F_XDEV)) {
rootdevs = calloc(argc - optind + 1, sizeof(dev_t));
r = 0;
}
if (ISFLAG(flags, F_RECURSEAFTER)) {
firstrecurse = nonoptafter("--recurse:", argc, oldargv, argv, optind);

Expand All @@ -1227,18 +1246,38 @@ int main(int argc, char **argv) {
}

/* F_RECURSE is not set for directories before --recurse: */
for (x = optind; x < firstrecurse; x++)
filecount += grokdir(argv[x], &files);
for (x = optind; x < firstrecurse; x++) {
if (ISFLAG(flags, F_XDEV)) {
dev_t this_dev = getdevice(argv[x]);
if (!samedev(this_dev, rootdevs))
rootdevs[r++] = this_dev;
}
filecount += grokdir(argv[x], &files, rootdevs);
}

/* Set F_RECURSE for directories after --recurse: */
SETFLAG(flags, F_RECURSE);

for (x = firstrecurse; x < argc; x++)
filecount += grokdir(argv[x], &files);
for (x = firstrecurse; x < argc; x++) {
if (ISFLAG(flags, F_XDEV)) {
dev_t this_dev = getdevice(argv[x]);
if (!samedev(this_dev, rootdevs))
rootdevs[r++] = this_dev;
}
filecount += grokdir(argv[x], &files, rootdevs);
}
} else {
for (x = optind; x < argc; x++)
filecount += grokdir(argv[x], &files);
for (x = optind; x < argc; x++) {
if (ISFLAG(flags, F_XDEV)) {
dev_t this_dev = getdevice(argv[x]);
if (!samedev(this_dev, rootdevs))
rootdevs[r++] = this_dev;
}
filecount += grokdir(argv[x], &files, rootdevs);
}
}
if (ISFLAG(flags, F_XDEV))
free(rootdevs);

if (!files) {
if (!ISFLAG(flags, F_HIDEPROGRESS)) fprintf(stderr, "\r%40s\r", " ");
Expand Down