-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsamearchive.cpp
More file actions
162 lines (146 loc) · 5.69 KB
/
samearchive.cpp
File metadata and controls
162 lines (146 loc) · 5.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
/* ************************************************************************ *
* samearchive - Reads the paths from the input and output the identical *
* files. This program is written for the special case *
* where each directory acts as an archive or backup. The *
* The output will only contain filename pairs that have the *
* same relative path from the archive base. *
* *
* Example: find /backup/ | samearchive <dir1> <dir2> [<dir 3> ...] *
* ************************************************************************ *
* Written by Alex de Kruijff 21 April 2009 *
* ************************************************************************ *
* This source was written with a tabstop every four characters *
* In vi type :set ts=4 *
* ************************************************************************ */
static const char version[] = "$Id: samearchive.cpp, v1.01 2009/04/14 00:00:00 akruijff Exp $\n";
#include "toolkit.h"
#include "stats.h"
#ifdef DEBUG
#include "debug.h"
#endif // DEBUG
// This file holds the engine code
#include "main.h"
static int argc;
static size_t *length;
static char **argv;
static int flags;
static const char *sep;
/**
* Prints the usage of this program.
*/
static void usage(const char *program) throw()
{
fprintf(stderr, "\n%s: read alist of filenames from stdin and", program);
fprintf(stderr, "\nwrites a list of identical files on stdout.\n");
fprintf(stderr, "\nusage: %s [-a | -A | -L | -Z | -At | -Az] [-g size] \\", program);
size_t len = strlen(program);
fprintf(stderr, "\n ");
for (size_t i = 0; i < len; ++i)
fprintf(stderr, " ");
fprintf(stderr, "[-l | -r] [-m size] [-S sep] [-0HiqVv] <dir1> <dir2> [...]");
fprintf(stderr, "\nexample: find <dir> | %s [options] <dir1> <dir2> [...]", program);
fprintf(stderr, "\n");
fprintf(stderr, "\n options: -A match based on the first filename (default)");
fprintf(stderr, "\n -a don't sort files with same size alphabetically");
fprintf(stderr, "\n -g only output files greater than size (0)");
fprintf(stderr, "\n -H human readable statistics");
fprintf(stderr, "\n -i add files with identical inodes");
fprintf(stderr, "\n -L match based on the number of links");
fprintf(stderr, "\n -l don't report hard linked filenames (default)");
fprintf(stderr, "\n -m only output files less or equal than size (0)");
fprintf(stderr, "\n -q suppress non-error messages");
fprintf(stderr, "\n -r report hard linked filenames");
fprintf(stderr, "\n -S use sep as separator string for files (tab)");
fprintf(stderr, "\n -t match based on the modiciation time \\");
fprintf(stderr, "\n instead of the alphabethical order");
fprintf(stderr, "\n -V output version information and exit");
fprintf(stderr, "\n -v increase verbosity");
fprintf(stderr, "\n -Z match based on the last filename");
fprintf(stderr, "\n");
exit(EXIT_SUCCESS);
}
inline int passCombination(const char *a, const char *b,
size_t len1, size_t len2)
{
for (size_t i = 0; i < argc; ++i) if (length[i] <= len1)
for (size_t j = i + 1; j < argc; ++j) if (length[j] <= len2)
if (!memcmp(argv[i], a, length[i]) &&
!memcmp(argv[j], b, length[j]) &&
!strcmp(a + length[i], b + length[j]))
return 0;
return 1;
}
static int preCheck(const SizeGroup &parent,
const FileGroup &left, const FileGroup &right) throw()
{
size_t leftBoundry = left.getBoundry();
size_t rightBoundry = right.getBoundry();
int output = 1;
for (size_t i = 0; i < leftBoundry; ++i) if (left[i] != NULL)
{
const char *a = left[i]->data();
size_t len1 = strlen(a);
for (size_t j = 0; j < rightBoundry; ++j) if (right[j] != NULL)
if (!passCombination(a, right[j]->data(),
len1, strlen(right[j]->data())))
return 0;
}
return 1;
}
static int selectResults(int flags, const char *sep)
{
::flags = flags;
::sep = sep;
return FILE_IDENTICAL | FILE_BY_LOGIC;
}
static int printFileCompare(const SizeGroup &parent,
const FileGroup &left, const Filename &leftChild,
const FileGroup &right, const Filename &rightChild,
int result) throw()
{
if (passCombination(leftChild.data(), rightChild.data(),
strlen(leftChild.data()), strlen(rightChild.data())))
return 0;
switch(result)
{
case FILE_IDENTICAL:
case FILE_IDENTICAL | FILE_BY_LOGIC:
outputSamefile(leftChild.data(), rightChild.data(),
left.stat().st_nlink, right.stat().st_nlink,
parent.getFileSize(), left.isOnSameDevice(right), sep);
break;
case FILE_OPEN1_ERROR:
if (S_VERBOSE_LEVEL1(flags))
fprintf(stderr, "inaccessible: %s\n", leftChild.data());
break;
case FILE_OPEN2_ERROR:
if (S_VERBOSE_LEVEL1(flags))
fprintf(stderr, "inaccessible: %s\n", rightChild.data());
break;
case FILE_READ1_ERROR:
if (S_VERBOSE_LEVEL1(flags))
fprintf(stderr, "unreadable: %s\n", leftChild.data());
break;
case FILE_READ2_ERROR:
if (S_VERBOSE_LEVEL1(flags))
fprintf(stderr, "unreadable: %s\n", rightChild.data());
}
return 0;
}
int main(int argc, char **argv)
{
_malloc_options = "H";
Stats stats;
int offset = processOptions(argc, argv, usage, version);
::argc = argc - offset;
::argv = argv + offset;
length = new size_t[::argc];
for (size_t i = 0; i < ::argc; ++i)
length[i] = strlen(::argv[i]);
processInput(stats, printFileCompare, selectResults, preCheck);
if (S_VERBOSE_LEVEL2(flags))
processStats(stats);
#ifdef DEBUG
checkDynamic();
#endif // DEBUG
}