Now able to list files existing in DIR1 which do not in DIR2.
authorFrancois Fleuret <francois@fleuret.org>
Sun, 7 Mar 2010 22:25:32 +0000 (23:25 +0100)
committerFrancois Fleuret <francois@fleuret.org>
Sun, 7 Mar 2010 22:25:32 +0000 (23:25 +0100)
Makefile
finddup.1
finddup.c

index 235ac49..d02a4d9 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -26,7 +26,7 @@ MAN_PATH = /usr/share/man/man1
 
 LDFLAGS=
 
-REVISION_NUMBER=\"$(shell cat REVISION_NUMBER)\"
+UNAME=\"$(shell uname -srmn)\"
 
 ifeq ($(DEBUG),yes)
   OPTIMIZE_FLAG = -ggdb3 -DDEBUG -fno-omit-frame-pointer
@@ -34,7 +34,7 @@ else
   OPTIMIZE_FLAG = -O2
 endif
 
-CFLAGS = -Wall -ansi -pedantic -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DREVISION_NUMBER=$(REVISION_NUMBER) $(OPTIMIZE_FLAG)
+CFLAGS = -Wall -ansi -pedantic -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DUNAME="$(UNAME)" $(OPTIMIZE_FLAG)
 
 all: finddup
 
index 36ae5a3..989cff9 100644 (file)
--- a/finddup.1
+++ b/finddup.1
@@ -10,7 +10,7 @@ finddup \- Find files common to several directories or not
 
 .SH "SYNOPSIS"
 
-\fBfinddup\fP [OPTION]... [FILE]...
+\fBfinddup\fP [OPTION]... DIR1 [[^]DIR2]
 
 .SH "DESCRIPTION"
 
@@ -18,6 +18,12 @@ finddup \- Find files common to several directories or not
 common to two directories or files existing in one directories and not
 in another one.
 
+With a single directory argument, prints the duplicate files found in
+it. With two directories, prints the files common to both.
+
+If the second directory name starts with a ^, prints the files
+existing in DIR1 which do not exist in DIR2.
+
 .SH "OPTIONS"
 .TP
 \fB-h\fR
@@ -28,7 +34,8 @@ shows the real path of the files
 
 .SH "BUGS"
 
-None known, probably many though.
+Every pair of different files with same content are listed, which
+results in K^2 printed lines when K files are similar.
 
 .SH "AUTHOR"
 
index 09c50d1..39a3df6 100644 (file)
--- a/finddup.c
+++ b/finddup.c
@@ -46,19 +46,11 @@ typedef int64_t size_sum_t;
 int ignore_dotfiles = 0; /* 1 means ignore files and directories
                             starting with a dot */
 
-int forced_width = 0; /* -1 means no width limit, strictly positive
-                         means limit, 0 means not active */
-
-int forced_height = 0; /* -1 means no height limit, strictly positive
-                           means limit, 0 means not active */
-
-int fancy_size_display = 0; /* 1 means to use floating values with K, M and G
-                               as units */
-
-int reverse_sorting = 0; /* 1 means to show the large ones first */
+int show_realpaths = 0; /* 1 means ignore files and directories
+                            starting with a dot */
 
-int show_top = 0; /* 1 means to show the top of the sorted list
-                     instead of the bottom */
+int show_progress = 1; /* 1 means show a progress bar when we are in a
+                          tty */
 
 /********************************************************************/
 
@@ -152,6 +144,8 @@ int same_content(struct file_with_size *f1, struct file_with_size *f2) {
 
       if(s1 == s2) {
         if(s1 == 0) {
+          close(fd1);
+          close(fd2);
           return 1;
         } else {
           if(strncmp(buffer1, buffer2, s1)) {
@@ -167,6 +161,8 @@ int same_content(struct file_with_size *f1, struct file_with_size *f2) {
       }
     }
   } else {
+    if(fd1 >= 0) { close(fd1); }
+    if(fd2 >= 0) { close(fd2); }
     return 0;
   }
 }
@@ -183,10 +179,10 @@ struct file_with_size *scan_directory(struct file_with_size *tail,
   struct dirent *dir_e;
   struct stat dummy;
   struct file_with_size *tmp;
-  char subname[BUFFER_SIZE];
+  char subname[PATH_MAX];
 
   if(lstat(name, &dummy) != 0) {
-    fprintf(stderr, "Can not stat %s: %s\n", name, strerror(errno));
+    fprintf(stderr, "Can not stat \"%s\": %s\n", name, strerror(errno));
     exit(EXIT_FAILURE);
   }
 
@@ -199,7 +195,7 @@ struct file_with_size *scan_directory(struct file_with_size *tail,
   if(dir) {
     while((dir_e = readdir(dir))) {
       if(!ignore_entry(dir_e->d_name)) {
-        snprintf(subname, BUFFER_SIZE, "%s/%s", name, dir_e->d_name);
+        snprintf(subname, PATH_MAX, "%s/%s", name, dir_e->d_name);
         tail = scan_directory(tail, subname);
       }
     }
@@ -221,13 +217,50 @@ struct file_with_size *scan_directory(struct file_with_size *tail,
 void start(const char *dirname1, const char *dirname2) {
   struct file_with_size *list1, *list2;
   struct file_with_size *node1, *node2;
+  int not_in, found;
+
+  if(dirname2[0] == '^') {
+    not_in = 1;
+    dirname2++;
+  } else {
+    not_in = 0;
+  }
+
   list1 = scan_directory(0, dirname1);
   list2 = scan_directory(0, dirname2);
 
-  for(node1 = list1; node1; node1 = node1->next) {
-    for(node2 = list2; node2; node2 = node2->next) {
-      if(node1->inode != node2->inode && same_files(node1, node2)) {
-        printf("%s %s \n", node1->filename, node2->filename);
+  if(not_in) {
+    for(node1 = list1; node1; node1 = node1->next) {
+      found = 0;
+
+      for(node2 = list2; !found && node2; node2 = node2->next) {
+        if(node1->inode != node2->inode && same_files(node1, node2)) {
+          found = 1;
+        }
+      }
+
+      if(!found) {
+        if(show_realpaths) {
+          printf("%s\n", realpath(node1->filename, 0));
+        } else {
+          printf("%s\n", node1->filename);
+        }
+      }
+    }
+
+  } else {
+
+    for(node1 = list1; node1; node1 = node1->next) {
+      for(node2 = list2; node2; node2 = node2->next) {
+        if(node1->inode != node2->inode && same_files(node1, node2)) {
+          if(show_realpaths) {
+            printf("%s %s\n",
+                   realpath(node1->filename, 0),
+                   realpath(node2->filename, 0));
+          } else {
+            printf("%s %s\n", node1->filename, node2->filename);
+          }
+        }
       }
     }
   }
@@ -247,7 +280,7 @@ int main(int argc, char **argv) {
   setlocale (LC_ALL, "");
 
   while (1) {
-    c = getopt(argc, argv, "h");
+    c = getopt(argc, argv, "hr");
     if (c == -1)
       break;
 
@@ -260,6 +293,10 @@ int main(int argc, char **argv) {
 
       break;
 
+    case 'r':
+      show_realpaths = 1;
+      break;
+
     default:
       exit(EXIT_FAILURE);
     }
@@ -267,8 +304,10 @@ int main(int argc, char **argv) {
 
   if(optind + 1 < argc) {
     start(argv[optind], argv[optind + 1]);
+  } else if(optind < argc) {
+    start(argv[optind], argv[optind]);
   } else {
-    fprintf(stderr, "%s [OPTIONS] <dir1> <dir2>\n", argv[0]);
+    fprintf(stderr, "%s [OPTIONS] <dir1> [[^]<dir2>]\n", argv[0]);
     exit(EXIT_FAILURE);
   }