/*
* Copyright (c) 2004-2005, Doug Harple. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of author nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id: file.c,v 1.10 2005/03/05 01:54:56 purgedhalo Exp $
*
*/
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <dirent.h>
#include <string.h>
#include <errno.h>
#include "clean_string.h"
#include "file.h"
#include "detox.h"
char badfiles[3][30] = {
".",
"..",
""
};
/*
* Renames file to a safe filename.
*/
unsigned char *parse_file(unsigned char *filename, struct detox_options *options)
{
unsigned char *old_filename, *old_filename_ptr, *new_filename;
unsigned char *work, *hold;
struct stat stat_info;
int err;
unsigned int len;
struct detox_sequence *sequence;
len = strlen(filename) + 1;
old_filename = malloc(len);
if (old_filename == NULL) {
fprintf(stderr, "out of memory: %s\n", strerror(errno));
return NULL;
}
memcpy(old_filename, filename, len);
old_filename_ptr = strrchr(old_filename, '/');
if (old_filename_ptr != NULL) {
old_filename_ptr++;
}
else {
old_filename_ptr = old_filename;
}
/*
* Do the actual filename cleaning
*/
sequence = options->sequence;
work = strdup(old_filename_ptr);
while (sequence != NULL && work != NULL) {
hold = sequence->cleaner(work, sequence->options);
if (work != NULL) {
free(work);
}
work = hold;
sequence = sequence->next;
}
if (work == NULL) {
return old_filename;
}
/* check to see if nothing changed */
if (strcmp(old_filename_ptr, work) == 0) {
return old_filename;
}
len = (old_filename_ptr - old_filename);
new_filename = malloc(len + strlen(work) + 1);
if (new_filename == NULL) {
fprintf(stderr, "out of memory: %s\n", strerror(errno));
free(work);
free(old_filename);
return NULL;
}
strncpy(new_filename, old_filename, len);
strcpy(new_filename + len, work);
free(work);
err = lstat(old_filename, &stat_info);
if (err == -1) {
free(new_filename);
return old_filename;
}
err = lstat(new_filename, &stat_info);
if (err != -1) {
fprintf(stderr, "Cannot rename %s to %s: file already exists\n",
old_filename, new_filename);
free(new_filename);
return old_filename;
}
if (options->verbose || options->dry_run) {
printf("%s -> %s\n", old_filename, new_filename);
}
if (options->dry_run) {
free(new_filename);
return old_filename;
}
err = rename(old_filename, new_filename);
if (err == -1) {
fprintf(stderr, "Cannot rename %s to %s: %s\n",
old_filename, new_filename, strerror(errno));
free(new_filename);
return old_filename;
}
free(old_filename);
return new_filename;
}
/*
* Handles directory.
*/
void parse_dir(unsigned char *indir, struct detox_options *options)
{
unsigned char *new_file, *work;
DIR *dir_handle;
struct dirent *dir_entry;
struct stat stat_info;
int check_file, x;
int err;
err = lstat(indir, &stat_info);
if (err == -1) {
return;
}
if (!S_ISDIR(stat_info.st_mode)) {
return;
}
new_file = (char *)malloc(strlen(indir) + 1024);
if (new_file == NULL) {
fprintf(stderr, "out of memory: %s\n", strerror(errno));
return;
}
dir_handle = opendir(indir);
if (dir_handle == NULL) {
fprintf(stderr, "unable to parse: %s\n", strerror(errno));
free(new_file);
return;
}
dir_entry = readdir(dir_handle);
while (dir_entry != NULL) {
check_file = 1;
for (x = 0; badfiles[x][0] != 0; x++) {
if (strcmp(dir_entry->d_name, badfiles[x]) == 0) {
check_file = 0;
break;
}
}
if (check_file) {
sprintf(new_file, "%s/%s", indir, dir_entry->d_name);
lstat(new_file, &stat_info);
if (S_ISDIR(stat_info.st_mode)) {
work = parse_file(new_file, options);
if (options->recurse) {
parse_dir(work, options);
}
free(work);
}
else if (S_ISREG(stat_info.st_mode)) {
work = parse_file(new_file, options);
free(work);
}
else if (options->special) {
parse_special(new_file, options);
}
}
dir_entry = readdir(dir_handle);
}
closedir(dir_handle);
}
/*
* Handles a special file.
*/
void parse_special(unsigned char *in, struct detox_options *options)
{
struct stat stat_info;
char *new_file, *work;
int err;
/* detox, then parse_dir if a symlink to a dir */
new_file = parse_file(in, options);
if (!new_file) {
return;
}
err = lstat(new_file, &stat_info);
if (err == -1) {
fprintf(stderr, "Unable to stat %s\n", in);
free(new_file);
return;
}
if (options->recurse && S_ISLNK(stat_info.st_mode)) {
work = malloc(1024);
if (!work) {
fprintf(stderr, "out of memory: %s\n", strerror(errno));
free(new_file);
return;
}
memset(work, 0, 1024);
err = readlink(new_file, work, 1023);
if (err == -1) {
fprintf(stderr, "Unable to read symbolic link %s\n", in);
free(work);
free(new_file);
}
err = lstat(work, &stat_info);
if (err == -1) {
fprintf(stderr, "Unable to follow symbolic link %s\n", in);
free(work);
free(new_file);
return;
}
if (S_ISDIR(stat_info.st_mode)) {
parse_dir(work, options);
}
free(work);
}
free(new_file);
}
syntax highlighted by Code2HTML, v. 0.9.1