mirror of
https://github.com/tcsenpai/awesome-linux-binaries.git
synced 2025-06-05 16:55:22 +00:00
379 lines
7.4 KiB
C
379 lines
7.4 KiB
C
/**
|
|
* This file is part of the Detox package.
|
|
*
|
|
* Copyright (c) Doug Harple <detox.dharple@gmail.com>
|
|
*
|
|
* For the full copyright and license information, please view the LICENSE
|
|
* file that was distributed with this source code.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#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"
|
|
|
|
static char badfiles[3][30] = {
|
|
".",
|
|
"..",
|
|
""
|
|
};
|
|
|
|
#define BUF_SIZE 1024
|
|
|
|
/*
|
|
* Internal function declarations
|
|
*/
|
|
static int ignore_file(unsigned char *filename, struct detox_options *options);
|
|
|
|
/*
|
|
* 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_old;
|
|
struct stat stat_info_new;
|
|
int err;
|
|
size_t len;
|
|
|
|
struct detox_sequence_entry *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;
|
|
}
|
|
|
|
/*
|
|
* Check for files that need to be ignored
|
|
*/
|
|
|
|
if (ignore_file(old_filename_ptr, options)) {
|
|
return old_filename;
|
|
}
|
|
|
|
/*
|
|
* Do the actual filename cleaning
|
|
*/
|
|
|
|
sequence = options->sequence_to_use;
|
|
|
|
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_old);
|
|
if (err == -1) {
|
|
free(new_filename);
|
|
return old_filename;
|
|
}
|
|
|
|
err = lstat(new_filename, &stat_info_new);
|
|
if (err != -1) { // New file exists
|
|
if (stat_info_old.st_dev != stat_info_new.st_dev || // Different device
|
|
stat_info_old.st_ino != stat_info_new.st_ino || // Different inode
|
|
stat_info_old.st_nlink > 1) // More than one hard link
|
|
{
|
|
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;
|
|
int err;
|
|
size_t new_file_length;
|
|
|
|
err = lstat(indir, &stat_info);
|
|
if (err == -1) {
|
|
return;
|
|
}
|
|
|
|
if (!S_ISDIR(stat_info.st_mode)) {
|
|
return;
|
|
}
|
|
|
|
new_file_length = strlen(indir) + 1024;
|
|
new_file = (char *)malloc(new_file_length);
|
|
if (new_file == NULL) {
|
|
fprintf(stderr, "out of memory: %s\n", strerror(errno));
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Parse directory
|
|
*/
|
|
|
|
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 for files that need to be ignored
|
|
*/
|
|
check_file = !ignore_file(dir_entry->d_name, options);
|
|
|
|
if (check_file) {
|
|
snprintf(new_file, new_file_length, "%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);
|
|
return;
|
|
}
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
/*
|
|
* Determines if the file should be ignored
|
|
*/
|
|
static int ignore_file(unsigned char *filename, struct detox_options *options)
|
|
{
|
|
struct detox_ignore_entry *ignore_walk;
|
|
int x;
|
|
|
|
for (x = 0; badfiles[x][0] != 0; x++) {
|
|
if (strcmp(filename, badfiles[x]) == 0) {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
ignore_walk = options->files_to_ignore;
|
|
while (ignore_walk != NULL) {
|
|
if (strcmp(filename, ignore_walk->filename) == 0) {
|
|
return 1;
|
|
}
|
|
ignore_walk = ignore_walk->next;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Renames file to a safe filename.
|
|
*/
|
|
void parse_inline(unsigned char *filename, struct detox_options *options)
|
|
{
|
|
struct detox_sequence_entry *sequence;
|
|
FILE *fp;
|
|
unsigned char *base, *work, *hold;
|
|
size_t buf_size;
|
|
|
|
if (filename != NULL) {
|
|
if (!(fp = fopen(filename, "r"))) {
|
|
fprintf(stderr, "%s: %s\n", filename, strerror(errno));
|
|
return;
|
|
}
|
|
}
|
|
else {
|
|
fp = stdin;
|
|
}
|
|
|
|
buf_size = BUF_SIZE;
|
|
base = malloc(buf_size);
|
|
if (base == NULL) {
|
|
fprintf(stderr, "out of memory: %s\n", strerror(errno));
|
|
return;
|
|
}
|
|
|
|
while (fgets(base, buf_size, fp)) {
|
|
while (strrchr(base, '\n') == NULL) {
|
|
work = realloc(base, buf_size + BUF_SIZE - 1);
|
|
if (!fgets(work + buf_size - 1, BUF_SIZE, fp)) {
|
|
base = work;
|
|
break;
|
|
}
|
|
base = work;
|
|
buf_size += BUF_SIZE - 1;
|
|
}
|
|
|
|
hold = strrchr(base, '\n');
|
|
if (hold == NULL) {
|
|
fprintf(stderr, "Unable to parse input\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
*hold = '\0';
|
|
|
|
work = strdup(base);
|
|
|
|
sequence = options->sequence_to_use;
|
|
|
|
while (sequence != NULL && work != NULL) {
|
|
hold = sequence->cleaner(work, sequence->options);
|
|
if (work != NULL) {
|
|
free(work);
|
|
}
|
|
work = hold;
|
|
|
|
sequence = sequence->next;
|
|
}
|
|
|
|
if (work != NULL) {
|
|
printf("%s\n", work);
|
|
}
|
|
else {
|
|
printf("\n");
|
|
}
|
|
}
|
|
}
|