"Fossies" - the Fresh Open Source Software Archive

Member "detox-1.4.5/src/file.c" (15 Aug 2021, 7559 Bytes) of package /linux/privat/detox-1.4.5.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. For more information about "file.c" see the Fossies "Dox" file reference documentation.

    1 /**
    2  * This file is part of the Detox package.
    3  *
    4  * Copyright (c) Doug Harple <detox.dharple@gmail.com>
    5  *
    6  * For the full copyright and license information, please view the LICENSE
    7  * file that was distributed with this source code.
    8  */
    9 
   10 #include "config.h"
   11 
   12 #include <sys/stat.h>
   13 #include <stdio.h>
   14 #include <stdlib.h>
   15 #include <unistd.h>
   16 #include <dirent.h>
   17 #include <string.h>
   18 #include <errno.h>
   19 
   20 #include "clean_string.h"
   21 #include "file.h"
   22 #include "detox.h"
   23 
   24 static char badfiles[3][30] = {
   25     ".",
   26     "..",
   27     ""
   28 };
   29 
   30 #define BUF_SIZE 1024
   31 
   32 /*
   33  * Internal function declarations
   34  */
   35 static int ignore_file(unsigned char *filename, struct detox_options *options);
   36 
   37 /*
   38  * Renames file to a safe filename.
   39  */
   40 unsigned char *parse_file(unsigned char *filename, struct detox_options *options)
   41 {
   42     unsigned char *old_filename, *old_filename_ptr, *new_filename;
   43     unsigned char *work, *hold;
   44 
   45     struct stat stat_info_old;
   46     struct stat stat_info_new;
   47     int err;
   48     size_t len;
   49 
   50     struct detox_sequence_entry *sequence;
   51 
   52     len = strlen(filename) + 1;
   53     old_filename = malloc(len);
   54     if (old_filename == NULL) {
   55         fprintf(stderr, "out of memory: %s\n", strerror(errno));
   56         return NULL;
   57     }
   58     memcpy(old_filename, filename, len);
   59 
   60     old_filename_ptr = strrchr(old_filename, '/');
   61     if (old_filename_ptr != NULL) {
   62         old_filename_ptr++;
   63     }
   64     else {
   65         old_filename_ptr = old_filename;
   66     }
   67 
   68     /*
   69      * Check for files that need to be ignored
   70      */
   71 
   72     if (ignore_file(old_filename_ptr, options)) {
   73         return old_filename;
   74     }
   75 
   76     /*
   77      * Do the actual filename cleaning
   78      */
   79 
   80     sequence = options->sequence_to_use;
   81 
   82     work = strdup(old_filename_ptr);
   83 
   84     while (sequence != NULL && work != NULL) {
   85         hold = sequence->cleaner(work, sequence->options);
   86         if (work != NULL) {
   87             free(work);
   88         }
   89         work = hold;
   90 
   91         sequence = sequence->next;
   92     }
   93 
   94     if (work == NULL) {
   95         return old_filename;
   96     }
   97 
   98     /* check to see if nothing changed */
   99     if (strcmp(old_filename_ptr, work) == 0) {
  100         return old_filename;
  101     }
  102 
  103     len = (old_filename_ptr - old_filename);
  104     new_filename = malloc(len + strlen(work) + 1);
  105     if (new_filename == NULL) {
  106         fprintf(stderr, "out of memory: %s\n", strerror(errno));
  107         free(work);
  108         free(old_filename);
  109         return NULL;
  110     }
  111 
  112     strncpy(new_filename, old_filename, len);
  113     strcpy(new_filename + len, work);
  114 
  115     free(work);
  116 
  117     err = lstat(old_filename, &stat_info_old);
  118     if (err == -1) {
  119         free(new_filename);
  120         return old_filename;
  121     }
  122 
  123     err = lstat(new_filename, &stat_info_new);
  124     if (err != -1) {    // New file exists
  125         if (stat_info_old.st_dev != stat_info_new.st_dev || // Different device
  126             stat_info_old.st_ino != stat_info_new.st_ino || // Different inode
  127             stat_info_old.st_nlink > 1) // More than one hard link
  128         {
  129             fprintf(stderr, "Cannot rename %s to %s: file already exists\n", old_filename, new_filename);
  130 
  131             free(new_filename);
  132             return old_filename;
  133         }
  134     }
  135 
  136     if (options->verbose || options->dry_run) {
  137         printf("%s -> %s\n", old_filename, new_filename);
  138     }
  139 
  140     if (options->dry_run) {
  141         free(new_filename);
  142         return old_filename;
  143     }
  144 
  145     err = rename(old_filename, new_filename);
  146     if (err == -1) {
  147         fprintf(stderr, "Cannot rename %s to %s: %s\n", old_filename, new_filename, strerror(errno));
  148         free(new_filename);
  149         return old_filename;
  150     }
  151 
  152     free(old_filename);
  153 
  154     return new_filename;
  155 }
  156 
  157 /*
  158  * Handles directory.
  159  */
  160 void parse_dir(unsigned char *indir, struct detox_options *options)
  161 {
  162     unsigned char *new_file, *work;
  163     DIR *dir_handle;
  164     struct dirent *dir_entry;
  165     struct stat stat_info;
  166     int check_file;
  167     int err;
  168     size_t new_file_length;
  169 
  170     err = lstat(indir, &stat_info);
  171     if (err == -1) {
  172         return;
  173     }
  174 
  175     if (!S_ISDIR(stat_info.st_mode)) {
  176         return;
  177     }
  178 
  179     new_file_length = strlen(indir) + 1024;
  180     new_file = (char *)malloc(new_file_length);
  181     if (new_file == NULL) {
  182         fprintf(stderr, "out of memory: %s\n", strerror(errno));
  183         return;
  184     }
  185 
  186     /*
  187      * Parse directory
  188      */
  189 
  190     dir_handle = opendir(indir);
  191     if (dir_handle == NULL) {
  192         fprintf(stderr, "unable to parse: %s\n", strerror(errno));
  193         free(new_file);
  194         return;
  195     }
  196 
  197     dir_entry = readdir(dir_handle);
  198 
  199     while (dir_entry != NULL) {
  200 
  201         /* 
  202          * Check for files that need to be ignored
  203          */
  204         check_file = !ignore_file(dir_entry->d_name, options);
  205 
  206         if (check_file) {
  207             snprintf(new_file, new_file_length, "%s/%s", indir, dir_entry->d_name);
  208 
  209             lstat(new_file, &stat_info);
  210             if (S_ISDIR(stat_info.st_mode)) {
  211                 work = parse_file(new_file, options);
  212                 if (options->recurse) {
  213                     parse_dir(work, options);
  214                 }
  215                 free(work);
  216             }
  217             else if (S_ISREG(stat_info.st_mode)) {
  218                 work = parse_file(new_file, options);
  219                 free(work);
  220             }
  221             else if (options->special) {
  222                 parse_special(new_file, options);
  223             }
  224         }
  225         dir_entry = readdir(dir_handle);
  226     }
  227     closedir(dir_handle);
  228 }
  229 
  230 /*
  231  * Handles a special file.
  232  */
  233 void parse_special(unsigned char *in, struct detox_options *options)
  234 {
  235     struct stat stat_info;
  236     char *new_file, *work;
  237     int err;
  238 
  239     /* detox, then parse_dir if a symlink to a dir */
  240     new_file = parse_file(in, options);
  241     if (!new_file) {
  242         return;
  243     }
  244 
  245     err = lstat(new_file, &stat_info);
  246     if (err == -1) {
  247         fprintf(stderr, "Unable to stat %s\n", in);
  248         free(new_file);
  249         return;
  250     }
  251 
  252     if (options->recurse && S_ISLNK(stat_info.st_mode)) {
  253         work = malloc(1024);
  254         if (!work) {
  255             fprintf(stderr, "out of memory: %s\n", strerror(errno));
  256             free(new_file);
  257             return;
  258         }
  259 
  260         memset(work, 0, 1024);
  261         err = readlink(new_file, work, 1023);
  262         if (err == -1) {
  263             fprintf(stderr, "Unable to read symbolic link %s\n", in);
  264             free(work);
  265             free(new_file);
  266             return;
  267         }
  268 
  269         err = lstat(work, &stat_info);
  270         if (err == -1) {
  271             fprintf(stderr, "Unable to follow symbolic link %s\n", in);
  272             free(work);
  273             free(new_file);
  274             return;
  275         }
  276 
  277         if (S_ISDIR(stat_info.st_mode)) {
  278             parse_dir(work, options);
  279         }
  280 
  281         free(work);
  282     }
  283     free(new_file);
  284 
  285 }
  286 
  287 /*
  288  * Determines if the file should be ignored
  289  */
  290 static int ignore_file(unsigned char *filename, struct detox_options *options)
  291 {
  292     struct detox_ignore_entry *ignore_walk;
  293     int x;
  294 
  295     for (x = 0; badfiles[x][0] != 0; x++) {
  296         if (strcmp(filename, badfiles[x]) == 0) {
  297             return 1;
  298         }
  299     }
  300 
  301     ignore_walk = options->files_to_ignore;
  302     while (ignore_walk != NULL) {
  303         if (strcmp(filename, ignore_walk->filename) == 0) {
  304             return 1;
  305         }
  306         ignore_walk = ignore_walk->next;
  307     }
  308 
  309     return 0;
  310 }
  311 
  312 /*
  313  * Renames file to a safe filename.
  314  */
  315 void parse_inline(unsigned char *filename, struct detox_options *options)
  316 {
  317     struct detox_sequence_entry *sequence;
  318     FILE *fp;
  319     unsigned char *base, *work, *hold;
  320     size_t buf_size;
  321 
  322     if (filename != NULL) {
  323         if (!(fp = fopen(filename, "r"))) {
  324             fprintf(stderr, "%s: %s\n", filename, strerror(errno));
  325             return;
  326         }
  327     }
  328     else {
  329         fp = stdin;
  330     }
  331 
  332     buf_size = BUF_SIZE;
  333     base = malloc(buf_size);
  334     if (base == NULL) {
  335         fprintf(stderr, "out of memory: %s\n", strerror(errno));
  336         return;
  337     }
  338 
  339     while (fgets(base, buf_size, fp)) {
  340         while (strrchr(base, '\n') == NULL) {
  341             work = realloc(base, buf_size + BUF_SIZE - 1);
  342             if (!fgets(work + buf_size - 1, BUF_SIZE, fp)) {
  343                 base = work;
  344                 break;
  345             }
  346             base = work;
  347             buf_size += BUF_SIZE - 1;
  348         }
  349 
  350         hold = strrchr(base, '\n');
  351         if (hold == NULL) {
  352             fprintf(stderr, "Unable to parse input\n");
  353             exit(EXIT_FAILURE);
  354         }
  355         *hold = '\0';
  356 
  357         work = strdup(base);
  358 
  359         sequence = options->sequence_to_use;
  360 
  361         while (sequence != NULL && work != NULL) {
  362             hold = sequence->cleaner(work, sequence->options);
  363             if (work != NULL) {
  364                 free(work);
  365             }
  366             work = hold;
  367 
  368             sequence = sequence->next;
  369         }
  370 
  371         if (work != NULL) {
  372             printf("%s\n", work);
  373         }
  374         else {
  375             printf("\n");
  376         }
  377     }
  378 }