116 lines
2.7 KiB
C
116 lines
2.7 KiB
C
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#include "config.h"
|
|
#include "corrupt.h"
|
|
#include "debug.h"
|
|
#include "dosfs.h"
|
|
|
|
static uint32_t xs_rand(uint32_t);
|
|
static uint32_t xs_randb(uint32_t *, uint32_t, uint32_t);
|
|
|
|
/*
|
|
* Finds the rule (if any) that matches the given file. If no rule
|
|
* matches, the function returns NULL.
|
|
*/
|
|
config_t *
|
|
match_rule(config_t *conf, dosfile_t *file)
|
|
{
|
|
config_t *cur;
|
|
int match;
|
|
|
|
for (cur = conf; cur != NULL; cur = cur->next) {
|
|
match = 0;
|
|
match += ((cur->filename[0] == '*' && cur->filename[1] == 0) ||
|
|
(!strncmp(cur->filename, file->fname, 8)));
|
|
|
|
match += ((cur->ext[0] == '*' && cur->ext[1] == 0) ||
|
|
(!strncmp(cur->ext, file->fext, 3)));
|
|
|
|
if (match >= 2)
|
|
return cur;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Corrupts the given dosfile_t according to conf.
|
|
*/
|
|
int
|
|
corrupt_file(dosfs_t *fsd, dosfile_t *file, config_t *conf, uint32_t *state)
|
|
{
|
|
uint32_t off, end;
|
|
int real_off;
|
|
unsigned char c;
|
|
struct conf_opts_t opts;
|
|
|
|
end = (conf->end) ? conf->end : file->ent.size;
|
|
|
|
opts = conf->opts;
|
|
for (off = conf->start; (off < end) && (off < file->ent.size);
|
|
off += xs_randb(state, conf->skip_a, conf->skip_b)) {
|
|
real_off = get_byte_offset(fsd, file, off);
|
|
if (real_off < 0) {
|
|
DPRINTF(("get_byte_offset returned %s", strerror(real_off * -1)));
|
|
return 0;
|
|
}
|
|
|
|
if (pread(fsd->ifd, &c, 1, real_off) == -1) {
|
|
perror("file read failed");
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* The fun part! Originally the plan was to check for each
|
|
* function (i.e., "is it zero or not") before running the
|
|
* operations, but zero shift, add, and xor should be just as
|
|
* efficient as a bunch of if statements. Might be flawed
|
|
* logic, let me know if it is!
|
|
*/
|
|
c = c >> opts.shr;
|
|
c = c << opts.shl;
|
|
c += opts.add;
|
|
c ^= opts.bit_xor;
|
|
|
|
if (pwrite(fsd->ifd, &c, 1, real_off) == -1) {
|
|
perror("file write failed");
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Generates a random number within two bounds.
|
|
*/
|
|
static uint32_t
|
|
xs_randb(uint32_t *state, uint32_t lower, uint32_t upper)
|
|
{
|
|
*state = xs_rand(*state);
|
|
/* if we're already between, just roll with it */
|
|
if (*state <= upper && *state >= lower) {
|
|
return *state;
|
|
}
|
|
return ((*state % (upper - lower)) + lower);
|
|
}
|
|
|
|
/*
|
|
* Implement xorshift for randomness
|
|
*/
|
|
static uint32_t
|
|
xs_rand(uint32_t in)
|
|
{
|
|
uint32_t out;
|
|
|
|
out = in;
|
|
out ^= in << 13;
|
|
out ^= out >> 17;
|
|
out ^= out << 5;
|
|
return out;
|
|
}
|