Bug #1319 » undo.patch
| undo/undo.c 2009-03-29 03:19:33 +0000 | ||
|---|---|---|
|
#define UNDO_FLAG_MULT 0x0001
|
||
|
#define UNDO_FLAG_INOCHG 0x0002
|
||
|
#define UNDO_FLAG_SETTID1 0x0004
|
||
|
#define UNDO_FLAG_SETTID2 0x0008
|
||
|
static int undo_hist_entry_compare(struct undo_hist_entry *he1,
|
||
|
struct undo_hist_entry *he2);
|
||
|
static void doiterate(const char *filename, const char *outFileName,
|
||
|
const char *outFilePostfix, int flags,
|
||
|
struct hammer_ioc_hist_entry ts1,
|
||
|
struct hammer_ioc_hist_entry ts2,
|
||
|
enum undo_cmd cmd, enum undo_type type);
|
||
|
static void dogenerate(const char *filename, const char *outFileName,
|
||
|
const char *outFilePostfix,
|
||
| ... | ... | |
|
static void collect_dir_history(const char *filename, int *error,
|
||
|
struct undo_hist_entry_rb_tree *dir_tree);
|
||
|
static void clean_tree(struct undo_hist_entry_rb_tree *tree);
|
||
|
static hammer_tid_t parse_delta_time(const char *timeStr);
|
||
|
static hammer_tid_t parse_delta_time(const char *timeStr, int *flags,
|
||
|
int ind_flag);
|
||
|
static void runcmd(int fd, const char *cmd, ...);
|
||
|
static char *timestamp(hammer_ioc_hist_entry_t hen);
|
||
|
static void usage(void);
|
||
| ... | ... | |
|
struct hammer_ioc_hist_entry ts1;
|
||
|
struct hammer_ioc_hist_entry ts2;
|
||
|
int c;
|
||
|
int count_t;
|
||
|
int flags;
|
||
|
bzero(&ts1, sizeof(ts1));
|
||
| ... | ... | |
|
cmd = CMD_DUMP;
|
||
|
type = TYPE_FILE;
|
||
|
count_t = 0;
|
||
|
flags = 0;
|
||
|
while ((c = getopt(ac, av, "adDiuvo:t:")) != -1) {
|
||
|
switch(c) {
|
||
| ... | ... | |
|
outFileName = optarg;
|
||
|
break;
|
||
|
case 't':
|
||
|
if (ts1.tid && ts2.tid)
|
||
|
usage();
|
||
|
else if (ts1.tid == 0)
|
||
|
ts1.tid = parse_delta_time(optarg);
|
||
|
++count_t;
|
||
|
if (count_t == 1)
|
||
|
ts1.tid = parse_delta_time(optarg, &flags,
|
||
|
UNDO_FLAG_SETTID1);
|
||
|
else if (count_t == 2)
|
||
|
ts2.tid = parse_delta_time(optarg, &flags,
|
||
|
UNDO_FLAG_SETTID2);
|
||
|
else
|
||
|
ts2.tid = parse_delta_time(optarg);
|
||
|
usage();
|
||
|
break;
|
||
|
default:
|
||
|
usage();
|
||
| ... | ... | |
|
ac -= optind;
|
||
|
av += optind;
|
||
|
flags = 0;
|
||
|
if (ac > 1)
|
||
|
flags |= UNDO_FLAG_MULT;
|
||
| ... | ... | |
|
while (ac) {
|
||
|
doiterate(*av, outFileName, outFilePostfix,
|
||
|
flags, ts1, cmd, type);
|
||
|
flags, ts1, ts2, cmd, type);
|
||
|
++av;
|
||
|
--ac;
|
||
|
}
|
||
| ... | ... | |
|
/*
|
||
|
* Iterate through a file's history. If cmd == CMD_DUMP we take the
|
||
|
* next-to-last transaction id. Otherwise if cmd == CMD_ITERATEALL
|
||
|
* we scan all transaction ids.
|
||
|
* next-to-last transaction id, unless another given. Otherwise if
|
||
|
* cmd == CMD_ITERATEALL we scan all transaction ids.
|
||
|
*
|
||
|
* Also iterate through the directory's history to locate other inodes that
|
||
|
* used the particular file name.
|
||
| ... | ... | |
|
doiterate(const char *filename, const char *outFileName,
|
||
|
const char *outFilePostfix, int flags,
|
||
|
struct hammer_ioc_hist_entry ts1,
|
||
|
struct hammer_ioc_hist_entry ts2,
|
||
|
enum undo_cmd cmd, enum undo_type type)
|
||
|
{
|
||
|
struct undo_hist_entry_rb_tree dir_tree;
|
||
|
struct undo_hist_entry_rb_tree tse_tree;
|
||
|
struct undo_hist_entry *tse1;
|
||
|
struct undo_hist_entry *tse2;
|
||
|
struct hammer_ioc_hist_entry ts2, tid_max;
|
||
|
struct hammer_ioc_hist_entry tid_max;
|
||
|
char *path = NULL;
|
||
|
int i;
|
||
|
int fd;
|
||
| ... | ... | |
|
}
|
||
|
}
|
||
|
if (cmd == CMD_DUMP) {
|
||
|
/*
|
||
|
* Single entry, most recent prior to current
|
||
|
*/
|
||
|
if (ts1.tid == 0 && RB_EMPTY(&tse_tree)) {
|
||
|
if ((ts1.tid == 0 ||
|
||
|
flags & (UNDO_FLAG_SETTID1|UNDO_FLAG_SETTID2)) &&
|
||
|
RB_EMPTY(&tse_tree)) {
|
||
|
if ((fd = open(filename, O_RDONLY)) > 0) {
|
||
|
collect_history(fd, &error, &tse_tree);
|
||
|
close(fd);
|
||
|
}
|
||
|
}
|
||
|
/*
|
||
|
* Find entry if tid set to placeholder index
|
||
|
*/
|
||
|
if (flags & UNDO_FLAG_SETTID1){
|
||
|
tse1 = RB_MAX(undo_hist_entry_rb_tree, &tse_tree);
|
||
|
while (tse1 && ts1.tid--)
|
||
|
tse1 = RB_PREV(undo_hist_entry_rb_tree,
|
||
|
&tse_tree, tse1);
|
||
|
if (tse1)
|
||
|
ts1 = tse1->tse;
|
||
|
else
|
||
|
ts1.tid = 0;
|
||
|
}
|
||
|
if (flags & UNDO_FLAG_SETTID2){
|
||
|
tse2 = RB_MAX(undo_hist_entry_rb_tree, &tse_tree);
|
||
|
while (tse2 && ts2.tid--)
|
||
|
tse2 = RB_PREV(undo_hist_entry_rb_tree,
|
||
|
&tse_tree, tse2);
|
||
|
if (tse2)
|
||
|
ts2 = tse2->tse;
|
||
|
else
|
||
|
ts2.tid = 0;
|
||
|
}
|
||
|
/*
|
||
|
* Single entry, most recent prior to current
|
||
|
*/
|
||
|
if (ts1.tid == 0) {
|
||
|
tse2 = RB_MAX(undo_hist_entry_rb_tree, &tse_tree);
|
||
|
if (tse2) {
|
||
| ... | ... | |
|
static
|
||
|
hammer_tid_t
|
||
|
parse_delta_time(const char *timeStr)
|
||
|
parse_delta_time(const char *timeStr, int *flags, int ind_flag)
|
||
|
{
|
||
|
hammer_tid_t tid;
|
||
|
tid = strtoull(timeStr, NULL, 0);
|
||
|
if (timeStr[0] == '+')
|
||
|
++timeStr;
|
||
|
if (timeStr[0] >= '0' && timeStr[0] <= '9' && timeStr[1] != 'x')
|
||
|
*flags |= ind_flag;
|
||
|
return(tid);
|
||
|
}
|
||