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

new options to deal with pathname matching #62

Open
wants to merge 2 commits 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
5 changes: 5 additions & 0 deletions README
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ Usage: fdupes [options] DIRECTORY...
prompting the user
-p --permissions don't consider files with different owner/group or
permission bits as duplicates
-b --basename don't consider files with different basenames (that's
the base file name with directory path excluded) as duplicates
-P --strip=N strip the indicated number of leading directory
components (at slashes), and consider files potential
matches only if the remaining pathnames are the same
-o --order=BY select sort order for output, linking and deleting; by
mtime (BY='time'; default) or filename (BY='name')
-i --reverse reverse order while sorting
Expand Down
9 changes: 9 additions & 0 deletions fdupes.1
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,15 @@ set of duplicates and delete the others without prompting the user
.B -p --permissions
don't consider files with different owner/group or permission bits as duplicates
.TP
.B -b --basename
don't consider files with different file basenames (that's the base file name with
the directory path excluded) as duplicates
.TP
.B -P --strip=N
strip the indicated number of leading directory components (at slashes),
and consider files potential matches only if the remaining pathnames
are the same
.TP
.B -o --order\fR=\fIWORD\fR
order files according to WORD:
time - sort by mtime, name - sort by filename
Expand Down
61 changes: 51 additions & 10 deletions fdupes.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
#define F_EXCLUDEHIDDEN 0x1000
#define F_PERMISSIONS 0x2000
#define F_REVERSE 0x4000
#define F_BASENAME 0x8000

typedef enum {
ORDER_TIME = 0,
Expand All @@ -63,6 +64,8 @@ char *program_name;

unsigned long flags = 0;

int stripdirs = 0;

#define CHUNK_SIZE 8192

#define INPUT_SIZE 256
Expand Down Expand Up @@ -91,6 +94,8 @@ typedef struct _signatures

typedef struct _file {
char *d_name;
char *d_basename;
char *d_strippedname;
off_t size;
md5_byte_t *crcpartial;
md5_byte_t *crcsignature;
Expand Down Expand Up @@ -249,7 +254,6 @@ int grokdir(char *dir, file_t **filelistp)
struct stat linfo;
static int progress = 0;
static char indicator[] = "-\\|/";
char *fullname, *name;

cd = opendir(dir);

Expand Down Expand Up @@ -291,19 +295,29 @@ int grokdir(char *dir, file_t **filelistp)

strcpy(newfile->d_name, dir);
lastchar = strlen(dir) - 1;
if (lastchar >= 0 && dir[lastchar] != '/')
strcat(newfile->d_name, "/");
strcat(newfile->d_name, dirinfo->d_name);
if (lastchar >= 0 && dir[lastchar] != '/') {
newfile->d_name[++lastchar] = '/';
}
newfile->d_basename = newfile->d_name + lastchar + 1;
strcpy(newfile->d_basename, dirinfo->d_name);

newfile->d_strippedname = newfile->d_name;
for (int i = 0 ; i < stripdirs ; ++i) {
newfile->d_strippedname = strchr(newfile->d_strippedname, '/');
if (! newfile->d_strippedname) {
break;
}
++newfile->d_strippedname;
}

if (ISFLAG(flags, F_EXCLUDEHIDDEN)) {
fullname = strdup(newfile->d_name);
name = basename(fullname);
if (name[0] == '.' && strcmp(name, ".") && strcmp(name, "..") ) {
if (newfile->d_basename[0] == '.'
&& strcmp(newfile->d_basename, ".")
&& strcmp(newfile->d_basename, "..") ) {
free(newfile->d_name);
free(newfile);
continue;
}
free(fullname);
}

if (filesize(newfile->d_name) == 0 && ISFLAG(flags, F_EXCLUDEEMPTY)) {
Expand Down Expand Up @@ -516,10 +530,20 @@ file_t **checkmatch(filetree_t **root, filetree_t *checktree, file_t *file)
cmpresult = -1;
else
if (fsize > checktree->file->size) cmpresult = 1;
else
if (ISFLAG(flags, F_BASENAME) &&
strcmp(file->d_basename, checktree->file->d_basename) != 0)
cmpresult = -1;
else
if (ISFLAG(flags, F_PERMISSIONS) &&
!same_permissions(file->d_name, checktree->file->d_name))
cmpresult = -1;
else
if (stripdirs > 0 &&
file->d_strippedname &&
checktree->file->d_strippedname &&
strcmp(file->d_strippedname, checktree->file->d_strippedname) != 0)
cmpresult = -1;
else {
if (checktree->file->crcpartial == NULL) {
crcsignature = getcrcpartialsignature(checktree->file->d_name);
Expand Down Expand Up @@ -1003,6 +1027,11 @@ void help_text()
printf(" \tprompting the user\n");
printf(" -p --permissions \tdon't consider files with different owner/group or\n");
printf(" \tpermission bits as duplicates\n");
printf(" -b --basename \tdon't consider files with different basenames (that's\n");
printf(" \tthe base file name with directory path excluded) as duplicates\n");
printf(" -P --strip=N \tstrip the indicated number of leading directory\n");
printf(" \tcomponents (at slashes), and consider files potential\n");
printf(" \tmatches only if the remaining pathnames are the same\n");
printf(" -o --order=BY \tselect sort order for output, linking and deleting; by\n");
printf(" \tmtime (BY='time'; default) or filename (BY='name')\n");
printf(" -i --reverse \treverse order while sorting\n");
Expand Down Expand Up @@ -1051,7 +1080,9 @@ int main(int argc, char **argv) {
{ "summarize", 0, 0, 'm'},
{ "summary", 0, 0, 'm' },
{ "permissions", 0, 0, 'p' },
{ "order", 1, 0, 'o' },
{ "basename", 0, 0, 'b' },
{ "strip", required_argument, 0, 'P' },
{ "order", required_argument, 0, 'o' },
{ "reverse", 0, 0, 'i' },
{ 0, 0, 0, 0 }
};
Expand All @@ -1064,7 +1095,7 @@ int main(int argc, char **argv) {

oldargv = cloneargs(argc, argv);

while ((opt = GETOPT(argc, argv, "frRq1SsHlnAdvhNmpo:i"
while ((opt = GETOPT(argc, argv, "frRq1SsHlnAdvhNmpbP:o:i"
#ifndef OMIT_GETOPT_LONG
, long_options, NULL
#endif
Expand Down Expand Up @@ -1118,6 +1149,16 @@ int main(int argc, char **argv) {
case 'p':
SETFLAG(flags, F_PERMISSIONS);
break;
case 'b':
SETFLAG(flags, F_BASENAME);
break;
case 'P':
stripdirs = atoi(optarg);
if (stripdirs == 0 && strcmp(optarg, "0") != 0) {
errormsg("invalid value for --strip: '%s'\n", optarg);
exit(1);
}
break;
case 'o':
if (!strcasecmp("name", optarg)) {
ordertype = ORDER_NAME;
Expand Down
1 change: 1 addition & 0 deletions testdir/basename_test/dir1/included_with_b_option
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Integer condimentum, massa non malesuada cursus, arcu tellus cursus tellus, vitae sodales diam erat eget sem. Nulla pulvinar lacus sed pulvinar sodales. Curabitur blandit, orci sed elementum efficitur, ipsum libero finibus lacus, nec varius nunc est at eros. Morbi feugiat libero quis lectus dictum pellentesque. Mauris scelerisque placerat neque non sodales. Proin elementum velit eget lacinia mollis. Aenean varius nunc lorem, id malesuada sapien mattis eu. Mauris sagittis diam ante, eget semper ipsum posuere in. Vivamus cursus ante vitae arcu vulputate, non feugiat mauris sollicitudin. Nam nec nisl at nunc elementum rhoncus. Suspendisse a ante et mi hendrerit vehicula. Aliquam diam ex, porta bibendum bibendum at, sagittis tempor velit. Aenean mattis enim nec velit vehicula feugiat. Sed non facilisis tortor, eget interdum neque. Donec malesuada, felis quis egestas accumsan, neque lectus scelerisque lectus, sit amet elementum tortor metus sit amet neque. Fusce efficitur gravida turpis ut pharetra.
1 change: 1 addition & 0 deletions testdir/basename_test/dir2/excluded_with_b_option
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Integer condimentum, massa non malesuada cursus, arcu tellus cursus tellus, vitae sodales diam erat eget sem. Nulla pulvinar lacus sed pulvinar sodales. Curabitur blandit, orci sed elementum efficitur, ipsum libero finibus lacus, nec varius nunc est at eros. Morbi feugiat libero quis lectus dictum pellentesque. Mauris scelerisque placerat neque non sodales. Proin elementum velit eget lacinia mollis. Aenean varius nunc lorem, id malesuada sapien mattis eu. Mauris sagittis diam ante, eget semper ipsum posuere in. Vivamus cursus ante vitae arcu vulputate, non feugiat mauris sollicitudin. Nam nec nisl at nunc elementum rhoncus. Suspendisse a ante et mi hendrerit vehicula. Aliquam diam ex, porta bibendum bibendum at, sagittis tempor velit. Aenean mattis enim nec velit vehicula feugiat. Sed non facilisis tortor, eget interdum neque. Donec malesuada, felis quis egestas accumsan, neque lectus scelerisque lectus, sit amet elementum tortor metus sit amet neque. Fusce efficitur gravida turpis ut pharetra.
1 change: 1 addition & 0 deletions testdir/basename_test/dir2/included_with_b_option
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Integer condimentum, massa non malesuada cursus, arcu tellus cursus tellus, vitae sodales diam erat eget sem. Nulla pulvinar lacus sed pulvinar sodales. Curabitur blandit, orci sed elementum efficitur, ipsum libero finibus lacus, nec varius nunc est at eros. Morbi feugiat libero quis lectus dictum pellentesque. Mauris scelerisque placerat neque non sodales. Proin elementum velit eget lacinia mollis. Aenean varius nunc lorem, id malesuada sapien mattis eu. Mauris sagittis diam ante, eget semper ipsum posuere in. Vivamus cursus ante vitae arcu vulputate, non feugiat mauris sollicitudin. Nam nec nisl at nunc elementum rhoncus. Suspendisse a ante et mi hendrerit vehicula. Aliquam diam ex, porta bibendum bibendum at, sagittis tempor velit. Aenean mattis enim nec velit vehicula feugiat. Sed non facilisis tortor, eget interdum neque. Donec malesuada, felis quis egestas accumsan, neque lectus scelerisque lectus, sit amet elementum tortor metus sit amet neque. Fusce efficitur gravida turpis ut pharetra.
1 change: 1 addition & 0 deletions testdir/pathstrip_test/subdir1/excluded_if_P_option_le_2
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Praesent nec placerat velit. Integer vel scelerisque sapien, in suscipit tellus. Mauris congue nisl quis mi maximus, eleifend pharetra sem lobortis. Aenean luctus enim a orci varius, non tincidunt justo vehicula. Quisque mattis quam faucibus lectus bibendum sagittis. Integer lobortis nulla nec ligula rutrum, vitae ultrices turpis porttitor. Quisque at lorem mollis, placerat purus nec, vestibulum mauris. Proin interdum posuere tempor. Proin blandit felis ut purus consequat, vitae laoreet sem ultrices.
1 change: 1 addition & 0 deletions testdir/pathstrip_test/subdir2/excluded_if_P_option_le_2
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Praesent nec placerat velit. Integer vel scelerisque sapien, in suscipit tellus. Mauris congue nisl quis mi maximus, eleifend pharetra sem lobortis. Aenean luctus enim a orci varius, non tincidunt justo vehicula. Quisque mattis quam faucibus lectus bibendum sagittis. Integer lobortis nulla nec ligula rutrum, vitae ultrices turpis porttitor. Quisque at lorem mollis, placerat purus nec, vestibulum mauris. Proin interdum posuere tempor. Proin blandit felis ut purus consequat, vitae laoreet sem ultrices.