int show_progress = 1; /* 1 means show a progress bar when we are in a
tty */
+int show_hits = 1; /* 1 means to show the files from dir2
+ corresponding to the ones from dir1 */
+
+int show_groups = 0; /* 1 means to show the group IDs when printing
+ file names */
+
/********************************************************************/
/* malloc with error checking. */
size_t size;
ino_t inode;
struct file_with_size *next;
- int error;
+ int id;
};
void file_list_delete(struct file_with_size *head) {
/**********************************************************************/
-int same_size(struct file_with_size *f1, struct file_with_size *f2) {
- return f1->size == f2->size;
-}
-
int same_content(struct file_with_size *f1, struct file_with_size *f2) {
int fd1, fd2, s1, s2;
char buffer1[BUFFER_SIZE], buffer2[BUFFER_SIZE];
}
}
} else {
- if(fd1 >= 0) { close(fd1); }
- if(fd2 >= 0) { close(fd2); }
- return 0;
+
+ if(fd1 < 0) {
+ fprintf(stderr,
+ "Can not open `%s' error: %s\n",
+ f1->filename,
+ strerror(errno));
+ }
+
+ if(fd2 < 0) {
+ fprintf(stderr,
+ "Can not open `%s' error: %s\n",
+ f2->filename,
+ strerror(errno));
+ }
+ exit(EXIT_FAILURE);
}
}
int same_files(struct file_with_size *f1, struct file_with_size *f2) {
- return same_size(f1, f2) && same_content(f1, f2);
+ return f1->size == f2->size && same_content(f1, f2);
}
/**********************************************************************/
const char *name) {
DIR *dir;
struct dirent *dir_e;
- struct stat dummy;
+ struct stat sb;
struct file_with_size *tmp;
char subname[PATH_MAX];
- if(lstat(name, &dummy) != 0) {
+ if(lstat(name, &sb) != 0) {
fprintf(stderr, "Can not stat \"%s\": %s\n", name, strerror(errno));
exit(EXIT_FAILURE);
}
- if(S_ISLNK(dummy.st_mode)) {
+ if(S_ISLNK(sb.st_mode)) {
return tail;
}
}
closedir(dir);
} else {
- if(S_ISREG(dummy.st_mode)) {
+ if(S_ISREG(sb.st_mode)) {
tmp = safe_malloc(sizeof(struct file_with_size));
tmp->next = tail;
tmp->filename = strdup(name);
- tmp->size = dummy.st_size;
- tmp->inode = dummy.st_ino;
+ tmp->size = sb.st_size;
+ tmp->inode = sb.st_ino;
+ tmp->id = -1;
tail = tmp;
}
}
return tail;
}
+void print_file(struct file_with_size *node) {
+ if(show_realpaths) {
+ if(show_groups) {
+ printf("%d %s\n", node->id, realpath(node->filename, 0));
+ } else {
+ printf("%s\n", realpath(node->filename, 0));
+ }
+ } else {
+ if(show_groups) {
+ printf("%d %s\n", node->id, node->filename);
+ } else {
+ printf("%s\n", node->filename);
+ }
+ }
+}
+
void start(const char *dirname1, const char *dirname2) {
struct file_with_size *list1, *list2;
struct file_with_size *node1, *node2;
- int not_in, found;
+ struct stat sb1, sb2;
+ int not_in, found, same_dir;
if(strncmp(dirname2, "not:", 4) == 0) {
not_in = 1;
not_in = 0;
}
+ if(lstat(dirname1, &sb1) != 0) {
+ fprintf(stderr, "Can not stat \"%s\": %s\n", dirname1, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ if(lstat(dirname2, &sb2) != 0) {
+ fprintf(stderr, "Can not stat \"%s\": %s\n", dirname2, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ same_dir = (sb1.st_ino == sb2.st_ino);
+
+ fprintf(stderr, "Scanning %s ... ", dirname1);
list1 = scan_directory(0, dirname1);
- list2 = scan_directory(0, dirname2);
+ if(same_dir) {
+ list2 = list1;
+ } else {
+ fprintf(stderr, " %s ... ", dirname2);
+ list2 = scan_directory(0, dirname2);
+ }
+ fprintf(stderr, "done.\n");
if(not_in) {
for(node1 = list1; node1; node1 = node1->next) {
}
} else {
+ int k = 0;
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);
+ if(node1->id < 0) {
+ if(node2->id >= 0) {
+ node1->id = node2->id;
+ } else {
+ node1->id = k;
+ k++;
+ }
+ print_file(node1);
+ }
+ if(node2->id < 0) {
+ node2->id = node1->id;
+ if(show_hits) {
+ print_file(node2);
+ }
}
}
}
}
file_list_delete(list1);
- file_list_delete(list2);
+ if(!same_dir) {
+ file_list_delete(list2);
+ }
}
void print_help(FILE *out) {
fprintf(out, "Version %s (%s)\n", VERSION_NUMBER, UNAME);
fprintf(out, "Without DIR2, lists duplicated files found in DIR1. With DIR2, lists files common to both directories. With the not: prefix, lists files found in DIR1 which do not exist in DIR2.\n");
fprintf(out, "\n");
- fprintf(out, " -h show this help.\n");
- fprintf(out, " -r show the real file paths.\n");
+ fprintf(out, " -h show this help\n");
+ fprintf(out, " -d ignore dot files and directories\n");
+ fprintf(out, " -c do not show which files in DIR2 corresponds to those in DIR1\n");
+ fprintf(out, " -g show the file groups\n");
+ fprintf(out, " -r show the real file paths\n");
fprintf(out, "\n");
fprintf(out, "Report bugs and comments to <francois@fleuret.org>\n");
}
setlocale (LC_ALL, "");
while (1) {
- c = getopt(argc, argv, "hr");
+ c = getopt(argc, argv, "hrcgd");
if (c == -1)
break;
break;
+ case 'd':
+ ignore_dotfiles = 1;
+ break;
+
case 'r':
show_realpaths = 1;
break;
+ case 'g':
+ show_groups = 1;
+ break;
+
+ case 'c':
+ show_hits = 0;
+ break;
+
default:
exit(EXIT_FAILURE);
}