Skip to content

Commit 767a85c

Browse files
committed
core: fix #60: Add --dupfile option to log dupes
1 parent f161578 commit 767a85c

13 files changed

Lines changed: 121 additions & 36 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/duplicut
22
/nonreg_*.out
3+
/nonregdupes_*.out
34
/objects
45
*.gcno
56
*.gcda

include/config.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ struct conf
66
{
77
const char *infile_name;
88
const char *outfile_name;
9+
const char *dupfile_name;
910
unsigned int threads;
1011
unsigned int line_max_size;
1112
size_t hmap_size;

include/const.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44
#define PROJECT_VERSION "2.3"
55
#define PROJECT_URL "http://github.com/nil0x42/duplicut"
66

7+
/* cast a preprocessor int to string */
8+
#define STR_HELPER(x) #x
9+
#define STR(x) STR_HELPER(x)
10+
711
/* portion of available memory to allow to hashmap */
812
#define HMAP_MAX_SIZE (0.5)
913

@@ -24,3 +28,6 @@
2428

2529
/* display program status periodically instead of waiting keypress */
2630
#define DEBUG_PROGRAM_STATUS (0)
31+
32+
/* max supported max-line-size */
33+
#define MAX_MAX_LINE_SIZE 4095

include/file.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,6 @@ struct file
1515
extern struct file *g_file;
1616

1717
/* source file: file.c */
18-
void init_file(const char *infile_name, const char *outfile_name);
19-
void destroy_file(void);
18+
void init_files(void);
19+
void cleanup_files(void);
20+
void log_duplicate(char *ln, int sz);

src/chunk.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ void cleanout_chunk(t_chunk *chunk)
103103
char *base_ptr;
104104
int i;
105105
long duplicates;
106+
const int has_dupfile = (g_conf.dupfile_name != NULL);
106107

107108
duplicates = 0;
108109
i = 0;
@@ -115,6 +116,9 @@ void cleanout_chunk(t_chunk *chunk)
115116
{
116117
if (cmp_line(&line, &g_hmap.ptr[slot]) == 0)
117118
{
119+
if (has_dupfile) {
120+
log_duplicate(LINE_ADDR(line), LINE_SIZE(line));
121+
}
118122
LINE_ADDR(line)[0] = DISABLED_LINE;
119123
++duplicates;
120124
break;

src/config.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,11 @@ void config(void)
128128
DLOG1("---------- g_conf ------------");
129129
DLOG1("g_conf.infile_name: %s", g_conf.infile_name);
130130
DLOG1("g_conf.outfile_name: %s", g_conf.outfile_name);
131+
if (g_conf.dupfile_name != NULL) {
132+
DLOG1("g_conf.dupfile_name: %s", g_conf.dupfile_name);
133+
} else {
134+
DLOG1("g_conf.dupfile_name: (null)");
135+
}
131136
DLOG1("g_conf.threads: %u", g_conf.threads);
132137
DLOG1("g_conf.line_max_size: %u", g_conf.line_max_size);
133138
DLOG1("g_conf.hmap_size: %s (%ld slots of %dbits)",

src/file.c

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <sys/types.h>
88
#include <ctype.h>
99
#include "file.h"
10+
#include "line.h"
1011
#include "const.h"
1112
#include "status.h"
1213
#include "error.h"
@@ -21,12 +22,15 @@
2122
static struct file g_infile;
2223
static struct file g_outfile;
2324
static struct file g_tmpfile;
25+
static struct file g_dupfile;
2426

2527

2628
/** Ensure that infile and outfile don't point to the same
2729
* file on filesystem, by comparing device & inode.
2830
*/
29-
static void check_files(const char *infile_name, const char *outfile_name)
31+
static void check_files_difer(
32+
const char *infile_name,
33+
const char *outfile_name)
3034
{
3135
struct stat infile_info;
3236
struct stat outfile_info;
@@ -62,6 +66,7 @@ static void close_all(void)
6266
{
6367
close_file(&g_infile);
6468
close_file(&g_outfile);
69+
close_file(&g_dupfile);
6570

6671
if (FILE_ISSET(&g_tmpfile))
6772
{
@@ -175,19 +180,24 @@ static void copy_file(int dst_fd, int src_fd, bool send_status)
175180
* - Registers cleanup functions with atexit()
176181
* - returned file has `addr` attribute mapped in memory
177182
*/
178-
void init_file(const char *infile_name, const char *outfile_name)
183+
void init_files(void)
179184
{
180185
struct file *file;
181186

182-
check_files(infile_name, outfile_name);
187+
check_files_difer(g_conf.infile_name, g_conf.outfile_name);
183188

184189
memset(&g_infile, -1, sizeof(g_infile));
185-
memset(&g_outfile, -1, sizeof(g_infile));
186-
memset(&g_tmpfile, -1, sizeof(g_infile));
190+
memset(&g_outfile, -1, sizeof(g_outfile));
191+
memset(&g_tmpfile, -1, sizeof(g_tmpfile));
192+
memset(&g_dupfile, -1, sizeof(g_dupfile));
187193

188194
atexit(close_all);
189-
open_file(&g_infile, infile_name, O_RDONLY);
190-
open_file(&g_outfile, outfile_name, O_TRUNC | O_CREAT | O_RDWR);
195+
open_file(&g_infile, g_conf.infile_name, O_RDONLY);
196+
open_file(&g_outfile, g_conf.outfile_name, O_TRUNC | O_CREAT | O_RDWR);
197+
198+
if (g_conf.dupfile_name != NULL) {
199+
open_file(&g_dupfile, g_conf.dupfile_name, O_TRUNC | O_CREAT | O_RDWR);
200+
}
191201

192202
if (S_ISREG(g_outfile.info.st_mode))
193203
file = &g_outfile;
@@ -230,7 +240,7 @@ void init_file(const char *infile_name, const char *outfile_name)
230240
* - truncate file with new size.
231241
* - Call close_all() for cleanout.
232242
*/
233-
void destroy_file(void)
243+
void cleanup_files(void)
234244
{
235245
struct file *file;
236246

@@ -252,3 +262,19 @@ void destroy_file(void)
252262

253263
close_all();
254264
}
265+
266+
/** Write a duplicate to dupfile_name (must be atomic)
267+
*/
268+
void log_duplicate(char *line_ptr, int line_sz)
269+
{
270+
ssize_t n;
271+
char buf[MAX_MAX_LINE_SIZE + 1];
272+
memcpy(buf, line_ptr, line_sz);
273+
buf[line_sz] = '\n';
274+
do {
275+
n = write(g_dupfile.fd, buf, line_sz + 1);
276+
} while (n == -1 && errno == EINTR);
277+
if (n == -1) {
278+
error("log_duplicate() -> write(): %s", ERRNO);
279+
}
280+
}

src/hmap.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
#include <stdlib.h>
2+
#include "file.h"
23
#include "hmap.h"
34
#include "hash.h"
5+
#include "line.h"
46
#include "const.h"
7+
#include "config.h"
58
#include "status.h"
69
#include "error.h"
710
#include "debug.h"
@@ -51,6 +54,7 @@ void populate_hmap(t_chunk *chunk)
5154
char *base_ptr;
5255
int i;
5356
long duplicates;
57+
const int has_dupfile = (g_conf.dupfile_name != NULL);
5458

5559
duplicates = 0;
5660
i = 0;
@@ -94,6 +98,9 @@ void populate_hmap(t_chunk *chunk)
9498
}
9599
else if (cmp_line(&line, &g_hmap.ptr[slot]) == 0)
96100
{
101+
if (has_dupfile) {
102+
log_duplicate(LINE_ADDR(line), LINE_SIZE(line));
103+
}
97104
LINE_ADDR(line)[0] = DISABLED_LINE;
98105
++duplicates;
99106
break;

src/main.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
struct conf g_conf = {
1616
.infile_name = NULL,
1717
.outfile_name = NULL,
18+
.dupfile_name = NULL,
1819
.threads = 0,
1920
.line_max_size = DEFAULT_LINE_MAX_SIZE,
2021
.hmap_size = 0,
@@ -76,7 +77,7 @@ int main(int argc, char **argv)
7677
watch_user_input();
7778

7879
update_status(FCOPY_START);
79-
init_file(g_conf.infile_name, g_conf.outfile_name);
80+
init_files();
8081
config(); /* configure g_conf options */
8182
set_status(CHUNK_SIZE, g_conf.chunk_size);
8283

@@ -87,7 +88,7 @@ int main(int argc, char **argv)
8788

8889
update_status(FCLEAN_START);
8990
remove_duplicates();
90-
destroy_file();
91+
cleanup_files();
9192

9293
display_report();
9394
return (0);

src/optparse.c

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
/** Arguments configuration for getopt_long().
1616
*/
17-
#define OPTSTRING "o:t:m:l:pcChv"
17+
#define OPTSTRING "o:t:m:l:pcCD:hv"
1818

1919
static struct option g_options[] = {
2020
{ "outfile", required_argument, NULL, 'o' },
@@ -24,6 +24,7 @@ static struct option g_options[] = {
2424
{ "printable", no_argument, NULL, 'p' },
2525
{ "lowercase", no_argument, NULL, 'c' },
2626
{ "uppercase", no_argument, NULL, 'C' },
27+
{ "dupfile", required_argument, NULL, 'D' },
2728
{ "help", no_argument, NULL, 'h' },
2829
{ "version", no_argument, NULL, 'v' },
2930
{ NULL, 0, NULL, '\0'},
@@ -63,6 +64,14 @@ static void setopt_outfile(const char *value)
6364
g_conf.outfile_name = value;
6465
}
6566

67+
/** Set dup file (-D option) [OPTIONAL]
68+
* --> The destination file
69+
*/
70+
static void setopt_dupfile(const char *value)
71+
{
72+
g_conf.dupfile_name = value;
73+
}
74+
6675

6776
static void setopt_threads(const char *value)
6877
{
@@ -109,9 +118,9 @@ static void setopt_line_max_size(const char *value)
109118
{
110119
bad_argument("line_max_size", value, "not a positive number");
111120
}
112-
else if (line_max_size > 4095)
121+
else if (line_max_size > MAX_MAX_LINE_SIZE)
113122
{
114-
bad_argument("line_max_size", value, "max value is 4095");
123+
bad_argument("line_max_size", value, "max value is " STR(MAX_MAX_LINE_SIZE));
115124
}
116125
g_conf.line_max_size = (unsigned int) line_max_size;
117126
}
@@ -155,6 +164,7 @@ static void setopt_help(const char *value)
155164
"-p, --printable Filter ascii printable lines\n"
156165
"-c, --lowercase Convert wordlist to lowercase\n"
157166
"-C, --uppercase Convert wordlist to uppercase\n"
167+
"-D, --dupfile <FILE> Write dupes to <FILE> (slows down duplicut)\n"
158168
"-h, --help Display this help and exit\n"
159169
"-v, --version Output version information and exit\n"
160170
"\n"
@@ -193,6 +203,7 @@ static void setopt(int opt, const char *value)
193203
{ 'p', setopt_printable },
194204
{ 'c', setopt_lowercase },
195205
{ 'C', setopt_uppercase },
206+
{ 'D', setopt_dupfile },
196207
{ 'h', setopt_help },
197208
{ 'v', setopt_version },
198209
{ '\0', NULL }

0 commit comments

Comments
 (0)