"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