blob: 1611f56fcacba1ead9d5fd3a4c3c0fcf28494e1c [file] [log] [blame]
/*
* Copyright 1996-2004 by Hans Reiser, licensing governed by
* reiserfsprogs/README
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "fsck.h"
#include "misc/malloc.h"
#include "util/misc.h"
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#define ROLLBACK_FILE_START_MAGIC "_RollBackFileForReiserfsFSCK"
static struct block_handler * rollback_blocks_array;
static __u32 rollback_blocks_number = 0;
static FILE * s_rollback_file = 0;
static FILE * log_file;
static int do_rollback = 0;
static char * rollback_data;
static unsigned int rollback_blocksize;
void fsck_rollback_init (char * rollback_file, unsigned int *blocksize, FILE * log) {
char * string;
struct stat buf;
if (rollback_file == NULL)
return;
stat(rollback_file, &buf);
s_rollback_file = fopen (rollback_file, "w+");
if (s_rollback_file == NULL) {
fprintf (stderr, "Cannot create file %s, work without "
"a rollback file\n", rollback_file);
return;
}
rollback_blocksize = *blocksize;
string = ROLLBACK_FILE_START_MAGIC;
fwrite (string, 28, 1, s_rollback_file);
fwrite (&rollback_blocksize, sizeof(rollback_blocksize),
1, s_rollback_file);
fwrite (&rollback_blocks_number, sizeof(rollback_blocks_number),
1, s_rollback_file);
fflush(s_rollback_file);
rollback_data = misc_getmem(rollback_blocksize);
// printf("\ncheckmem1");
// fflush (stdout);
// checkmem (rollback_data, misc_memsize((char *)rollback_data));
// printf(" OK");
log_file = log;
if (log_file)
fprintf (log_file, "rollback: file (%s) initialize\n", rollback_file);
do_rollback = 0;
}
#if 0
static void erase_rollback_file (char * rollback_file) {
close_rollback_file ();
unlink (rollback_file);
}
#endif
int fsck_rollback_prep (char * rollback_file, FILE * log) {
char string [28];
struct stat buf;
if (rollback_file == NULL)
return -1;
if (stat(rollback_file, &buf)) {
fprintf (stderr, "Cannot stat rollback file (%s)\n", rollback_file);
return -1;
}
s_rollback_file = fopen (rollback_file, "r+");
if (s_rollback_file == NULL) {
fprintf (stderr, "Cannot open file (%s)\n", rollback_file);
return -1;
}
fread (string, 28, 1, s_rollback_file);
if (!strcmp (string, ROLLBACK_FILE_START_MAGIC)) {
fprintf (stderr, "Specified file (%s) does not look like "
"a rollback file\n", rollback_file);
fclose (s_rollback_file);
s_rollback_file = 0;
return -1;
}
fread (&rollback_blocksize, sizeof (rollback_blocksize),
1, s_rollback_file);
if (rollback_blocksize <= 0) {
fprintf(stderr, "rollback: wrong rollback blocksize, exit\n");
return -1;
}
log_file = log;
if (log_file)
fprintf (log_file, "rollback: file (%s) opened\n", rollback_file);
do_rollback = 1;
return 0;
}
void fsck_rollback_fini () {
if (s_rollback_file == 0)
return;
if (!do_rollback) {
if (fseek (s_rollback_file, 28 + sizeof(int), SEEK_SET) == (off_t)-1)
return;
fwrite (&rollback_blocks_number,
sizeof (rollback_blocksize),
1, s_rollback_file);
if (log_file != 0) {
fprintf (log_file, "rollback: %d blocks backed up\n",
rollback_blocks_number);
}
}
fclose (s_rollback_file);
misc_freemem (rollback_data);
misc_freemem (rollback_blocks_array);
/*
fprintf (stdout, "rollback: (%u) blocks saved, \n",
rollback_blocks_number);
for (i = 0; i < rollback_blocks_number; i++)
fprintf(stdout, "device (%Lu), block number (%u)\n",
rollback_blocks_array [i].device,
rollback_blocks_array [i].blocknr);
fprintf(stdout, "\n");
*/
}
void fsck_rollback (int fd_device, int fd_journal_device, FILE * progress) {
long long int offset;
struct stat buf;
int descriptor;
ssize_t retval;
int count_failed = 0;
int count_rollbacked = 0;
int b_dev;
int n_dev = 0;
int n_journal_dev = 0;
unsigned long total, done = 0;
if (fd_device == 0) {
fprintf(stderr, "rollback: unspecified device, exit\n");
return;
}
if (fd_journal_device) {
if (!fstat (fd_journal_device, &buf)) {
n_journal_dev = buf.st_rdev;
} else {
fprintf(stderr, "rollback: specified journal device "
"cannot be stated\n");
}
}
if (!fstat (fd_device, &buf)) {
n_dev = buf.st_rdev;
} else {
fprintf(stderr, "rollback: specified device cannot "
"be stated, exit\n");
return;
}
rollback_data = misc_getmem (rollback_blocksize);
// printf("\ncheckmem2");
// fflush (stdout);
// checkmem (rollback_data, misc_memsize((char *)rollback_data));
// printf(" OK");
fread (&rollback_blocks_number,
sizeof (rollback_blocks_number),
1, s_rollback_file);
total = rollback_blocks_number;
while (1) {
if (!fsck_quiet(fs)) {
util_misc_progress (progress, &done,
rollback_blocks_number,
1, 0);
}
descriptor = 0;
if ((retval = fread (&b_dev, sizeof (b_dev),
1, s_rollback_file)) <= 0)
{
if (retval)
fprintf (stderr, "rollback: fread: %s\n", strerror (errno));
break;
}
if ((retval = fread (&offset, sizeof (offset),
1, s_rollback_file)) <= 0)
{
if (retval)
fprintf (stderr, "rollback: fread: %s\n", strerror (errno));
break;
}
if ((retval = fread (rollback_data, rollback_blocksize,
1, s_rollback_file)) <= 0)
{
if (retval)
fprintf (stderr, "rollback: fread: %s\n", strerror (errno));
break;
}
if (n_dev == b_dev)
descriptor = fd_device;
if ((n_journal_dev) && (n_journal_dev == b_dev))
descriptor = fd_journal_device;
if (descriptor == 0) {
fprintf(stderr, "rollback: block from unknown "
"device, skip block\n");
count_failed ++;
continue;
}
if (lseek (descriptor, offset, SEEK_SET) == (off_t)-1) {
fprintf(stderr, "device cannot be lseeked, skip block\n");
count_failed ++;
continue;
}
if (write (descriptor, rollback_data, rollback_blocksize) == -1) {
fprintf (stderr, "rollback: write %d bytes returned error "
"(block=%lld, dev=%d): %s\n", rollback_blocksize,
offset/rollback_blocksize, b_dev, strerror (errno));
count_failed ++;
} else {
count_rollbacked ++;
/*if you want to know what gets rollbacked, uncomment it*/
/* if (log_file != 0 && log_file != stdout)
fprintf (log_file, "rollback: block %Lu of "
"device %Lu was restored\n",
(unsigned long long)offset/rollback_blocksize, b_dev);
fprintf (stdout, "rollback: block (%Ld) written\n",
(long long int)offset/rollback_blocksize);
*/
}
}
printf ("\n");
if (log_file != 0) {
fprintf (log_file, "rollback: (%u) blocks restored\n",
count_rollbacked);
}
}
/*
static void rollback__mark_block_saved (struct block_handler * rb_e) {
if (rollback_blocks_array == NULL)
rollback_blocks_array =
misc_getmem (ROLLBACK__INCREASE_BLOCK_NUMBER * sizeof (*rb_e));
if (rollback_blocks_number ==
misc_memsize ((void *)rollback_blocks_array) / sizeof (*rb_e))
{
rollback_blocks_array =
misc_expandmem (rollback_blocks_array,
misc_memsize((void *)rollback_blocks_array),
ROLLBACK__INCREASE_BLOCK_NUMBER *
sizeof (*rb_e));
}
// checkmem ((char *)rollback_blocks_array,
misc_memsize((char *)rollback_blocks_array));
rollback_blocks_array[rollback_blocks_number] = *rb_e;
rollback_blocks_number ++;
qsort (rollback_blocks_array, rollback_blocks_number,
sizeof (*rb_e), rollback_compare);
// printf("\ncheckmem3");
// fflush (stdout);
// checkmem ((char *)rollback_blocks_array,
misc_memsize((char *)rollback_blocks_array));
// printf(" OK");
}
*/