"Fossies" - the Fresh Open Source Software Archive 
Member "duff-0.5.2/src/duffutil.c" (28 Jan 2012, 8130 Bytes) of package /linux/privat/old/duff-0.5.2.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
1 /*
2 * duff - Duplicate file finder
3 * Copyright (c) 2005 Camilla Berglund <elmindreda@elmindreda.org>
4 *
5 * This software is provided 'as-is', without any express or implied
6 * warranty. In no event will the authors be held liable for any
7 * damages arising from the use of this software.
8 *
9 * Permission is granted to anyone to use this software for any
10 * purpose, including commercial applications, and to alter it and
11 * redistribute it freely, subject to the following restrictions:
12 *
13 * 1. The origin of this software must not be misrepresented; you
14 * must not claim that you wrote the original software. If you use
15 * this software in a product, an acknowledgment in the product
16 * documentation would be appreciated but is not required.
17 *
18 * 2. Altered source versions must be plainly marked as such, and
19 * must not be misrepresented as being the original software.
20 *
21 * 3. This notice may not be removed or altered from any source
22 * distribution.
23 */
24
25 #if HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28
29 #if HAVE_SYS_TYPES_H
30 #include <sys/types.h>
31 #endif
32
33 #if HAVE_SYS_STAT_H
34 #include <sys/stat.h>
35 #endif
36
37 #if HAVE_STDIO_H
38 #include <stdio.h>
39 #endif
40
41 #if HAVE_STDLIB_H
42 #include <stdlib.h>
43 #endif
44
45 #if HAVE_STDARG_H
46 #include <stdarg.h>
47 #endif
48
49 #if HAVE_INTTYPES_H
50 #include <inttypes.h>
51 #elif HAVE_STDINT_H
52 #include <stdint.h>
53 #endif
54
55 #if HAVE_STRING_H
56 #include <string.h>
57 #endif
58
59 #if HAVE_CTYPE_H
60 #include <ctype.h>
61 #endif
62
63 #include "sha1.h"
64 #include "sha256.h"
65 #include "sha384.h"
66 #include "sha512.h"
67
68 #include "duffstring.h"
69 #include "duff.h"
70
71 /* These flags are defined and documented in duff.c.
72 */
73 extern int null_terminate_flag;
74
75 /* The message digest function to use.
76 */
77 static Function digest_function = SHA_1;
78
79 /* Union of all used SHA family contexts.
80 */
81 union Context
82 {
83 SHA1Context sha1;
84 SHA256Context sha256;
85 SHA384Context sha384;
86 SHA512Context sha512;
87 };
88
89 /* The context(s) used by the digest helper functions.
90 */
91 static union Context context;
92
93 /* Initializes a list for use.
94 */
95 void init_file_list(FileList* list)
96 {
97 memset(list, 0, sizeof(FileList));
98 }
99
100 /* Allocates and returns a single file within the specified list, resizing the
101 * list as necessary.
102 */
103 File* alloc_file(FileList* list)
104 {
105 if (list->allocated == list->available)
106 {
107 size_t count;
108
109 if (list->available)
110 count = list->available * 2;
111 else
112 count = 128;
113
114 list->files = realloc(list->files, count * sizeof(File));
115 if (list->files == NULL)
116 error(_("Out of memory"));
117
118 list->available = count;
119 }
120
121 File* file = list->files + list->allocated;
122 list->allocated++;
123 return file;
124 }
125
126 /* Empties the list without freeing its allocated memory.
127 */
128 void empty_file_list(FileList* list)
129 {
130 list->allocated = 0;
131 }
132
133 /* Frees the memory allocated by the list and reinitializes it.
134 */
135 void free_file_list(FileList* list)
136 {
137 free(list->files);
138 init_file_list(list);
139 }
140
141 /* Reads a path name from the specified stream according to the specified flags.
142 */
143 char* read_path(FILE* stream)
144 {
145 size_t capacity = 0, size = 0;
146 char* path = NULL;
147 char terminator = get_field_terminator();
148
149 for (;;)
150 {
151 const int c = fgetc(stream);
152 if (c == EOF && size == 0)
153 return NULL;
154
155 if (size == capacity)
156 {
157 capacity += 256;
158 path = (char*) realloc(path, capacity);
159 if (!path)
160 error(_("Out of memory"));
161 }
162
163 if (c == EOF || c == terminator)
164 break;
165
166 path[size++] = (char) c;
167 }
168
169 path[size] = '\0';
170 return path;
171 }
172
173 /* Kills trailing slashes in the specified path (except if it's /).
174 */
175 void kill_trailing_slashes(char* path)
176 {
177 char* temp;
178
179 while ((temp = strrchr(path, '/')))
180 {
181 if (temp == path || *(temp + 1) != '\0')
182 break;
183 *temp = '\0';
184 }
185 }
186
187 /* Returns the current field terminator used for stdin and stdout.
188 */
189 size_t get_field_terminator(void)
190 {
191 if (null_terminate_flag)
192 return '\0';
193 else
194 return '\n';
195 }
196
197 /* Sets the SHA family function to be used by the digest helpers.
198 */
199 void set_digest_function(Function function)
200 {
201 digest_function = function;
202 }
203
204 /*! Returns the size, in bytes, of the specified digest type.
205 */
206 size_t get_digest_size(void)
207 {
208 switch (digest_function)
209 {
210 case SHA_1:
211 return SHA1_HASH_SIZE;
212 case SHA_256:
213 return SHA256_HASH_SIZE;
214 case SHA_384:
215 return SHA384_HASH_SIZE;
216 case SHA_512:
217 return SHA512_HASH_SIZE;
218 }
219
220 error(_("This cannot happen"));
221 }
222
223 /* Initializes the context for the current function.
224 */
225 void digest_init(void)
226 {
227 switch (digest_function)
228 {
229 case SHA_1:
230 SHA1Init(&context.sha1);
231 return;
232 case SHA_256:
233 SHA256Init(&context.sha256);
234 return;
235 case SHA_384:
236 SHA384Init(&context.sha384);
237 return;
238 case SHA_512:
239 SHA512Init(&context.sha512);
240 return;
241 }
242
243 error(_("This cannot happen"));
244 }
245
246 /* Updates the context for the current function.
247 */
248 void digest_update(const void* data, size_t size)
249 {
250 switch (digest_function)
251 {
252 case SHA_1:
253 SHA1Update(&context.sha1, data, size);
254 return;
255 case SHA_256:
256 SHA256Update(&context.sha256, data, size);
257 return;
258 case SHA_384:
259 SHA384Update(&context.sha384, data, size);
260 return;
261 case SHA_512:
262 SHA512Update(&context.sha512, data, size);
263 return;
264 }
265
266 error(_("This cannot happen"));
267 }
268
269 /* Finalizes the digest of the chosen function.
270 */
271 void digest_finish(uint8_t* digest)
272 {
273 switch (digest_function)
274 {
275 case SHA_1:
276 SHA1Final(&context.sha1, digest);
277 return;
278 case SHA_256:
279 SHA256Final(&context.sha256, digest);
280 return;
281 case SHA_384:
282 SHA384Final(&context.sha384, digest);
283 return;
284 case SHA_512:
285 SHA512Final(&context.sha512, digest);
286 return;
287 }
288
289 error(_("This cannot happen"));
290 }
291
292 /* Prints a formatted message to stderr and exist with non-zero status.
293 */
294 void error(const char* format, ...)
295 {
296 char* message;
297 int result;
298 va_list vl;
299
300 va_start(vl, format);
301 result = vasprintf(&message, format, vl);
302 va_end(vl);
303
304 if (result > 0)
305 {
306 fprintf(stderr, "%s: %s\n", PACKAGE_NAME, message);
307 free(message);
308 }
309
310 exit(EXIT_FAILURE);
311 }
312
313 /* Prints a formatted message to stderr.
314 */
315 void warning(const char* format, ...)
316 {
317 char* message;
318 int result;
319 va_list vl;
320
321 va_start(vl, format);
322 result = vasprintf(&message, format, vl);
323 va_end(vl);
324
325 if (result > 0)
326 {
327 fprintf(stderr, "%s: %s\n", PACKAGE_NAME, message);
328 free(message);
329 }
330 }
331
332 /* Checks whether the cluster header format string uses file digests.
333 */
334 int cluster_header_uses_digest(const char* format)
335 {
336 const char* c;
337
338 for (c = format; *c != '\0'; c++)
339 {
340 if (*c == '%')
341 {
342 c++;
343 if (*c == 'c' || *c == 'd')
344 return 1;
345 if (*c == '\0')
346 break;
347 }
348 }
349
350 return 0;
351 }
352
353 /* Prints a duplicate cluster header to stdout. Various escape
354 * sequences in the format string are replaced with the provided values.
355 * Note that this function does not terminate the output with any
356 * special character (i.e. newline or null).
357 */
358 void print_cluster_header(const char* format,
359 unsigned int count,
360 unsigned int index,
361 off_t size,
362 const uint8_t* digest)
363 {
364 int i, digest_size;
365 const char* c;
366
367 for (c = format; *c != '\0'; c++)
368 {
369 if (*c == '%')
370 {
371 c++;
372 switch (*c)
373 {
374 case 's':
375 printf("%" PRIi64, size);
376 break;
377 case 'i':
378 printf("%u", index);
379 break;
380 case 'n':
381 printf("%u", count);
382 break;
383 case 'c':
384 case 'd':
385 digest_size = get_digest_size();
386 for (i = 0; i < digest_size; i++)
387 printf("%02x", digest[i]);
388 break;
389 case '%':
390 putchar('%');
391 break;
392 case '\0':
393 putchar('\n');
394 return;
395 default:
396 /* If the character following the '%' looks normal then we figure it
397 * might be a good idea to silently prepend a '%' and pretend like we
398 * didn't notice the broken format string.
399 */
400 if (isgraph(*c) || isspace(*c))
401 {
402 putchar('%');
403 putchar(*c);
404 }
405 }
406 }
407 else
408 putchar(*c);
409 }
410 }
411