| 70 |
70 |
|
| 71 |
71 |
#define UNDO_FLAG_MULT 0x0001
|
| 72 |
72 |
#define UNDO_FLAG_INOCHG 0x0002
|
|
73 |
#define UNDO_FLAG_SETTID1 0x0004
|
|
74 |
#define UNDO_FLAG_SETTID2 0x0008
|
| 73 |
75 |
|
| 74 |
76 |
static int undo_hist_entry_compare(struct undo_hist_entry *he1,
|
| 75 |
77 |
struct undo_hist_entry *he2);
|
| ... | ... | |
| 108 |
110 |
enum undo_type type;
|
| 109 |
111 |
struct hammer_ioc_hist_entry ts1;
|
| 110 |
112 |
struct hammer_ioc_hist_entry ts2;
|
| 111 |
|
int c;
|
|
113 |
int c, i;
|
| 112 |
114 |
int flags;
|
| 113 |
115 |
|
| 114 |
116 |
bzero(&ts1, sizeof(ts1));
|
| ... | ... | |
| 116 |
118 |
|
| 117 |
119 |
cmd = CMD_DUMP;
|
| 118 |
120 |
type = TYPE_FILE;
|
|
121 |
flags = 0;
|
| 119 |
122 |
|
| 120 |
|
while ((c = getopt(ac, av, "adDiuvo:t:")) != -1) {
|
|
123 |
i = -1;
|
|
124 |
while ((c = getopt(ac, av, "adDiuvo:t:0123456789")) != -1) {
|
|
125 |
if (c >= '0' && c <= '9') {
|
|
126 |
c -= '0';
|
|
127 |
i = (i >= 0) ? i*10 + c : c;
|
|
128 |
continue;
|
|
129 |
} else if (i >= 0) INDEX_ARG: {
|
|
130 |
/* set placeholder IDs for later lookup */
|
|
131 |
if (ts1.tid == 0 && !(flags & UNDO_FLAG_SETTID1))
|
|
132 |
ts1.tid = i, flags |= UNDO_FLAG_SETTID1;
|
|
133 |
else if (ts2.tid == 0 && !(flags & UNDO_FLAG_SETTID2))
|
|
134 |
ts2.tid = i, flags |= UNDO_FLAG_SETTID2;
|
|
135 |
else
|
|
136 |
usage();
|
|
137 |
i = -1;
|
|
138 |
if (c == -1)
|
|
139 |
/* got here after loop */
|
|
140 |
break;
|
|
141 |
}
|
| 121 |
142 |
switch(c) {
|
| 122 |
143 |
case 'd':
|
| 123 |
144 |
if (type != TYPE_FILE)
|
| ... | ... | |
| 148 |
169 |
outFileName = optarg;
|
| 149 |
170 |
break;
|
| 150 |
171 |
case 't':
|
| 151 |
|
if (ts1.tid && ts2.tid)
|
| 152 |
|
usage();
|
| 153 |
|
else if (ts1.tid == 0)
|
|
172 |
if (ts1.tid == 0 && !(flags & UNDO_FLAG_SETTID1))
|
| 154 |
173 |
ts1.tid = parse_delta_time(optarg);
|
| 155 |
|
else
|
|
174 |
else if (ts2.tid == 0 && !(flags & UNDO_FLAG_SETTID2))
|
| 156 |
175 |
ts2.tid = parse_delta_time(optarg);
|
|
176 |
else
|
|
177 |
usage();
|
| 157 |
178 |
break;
|
| 158 |
179 |
default:
|
| 159 |
180 |
usage();
|
| ... | ... | |
| 161 |
182 |
break;
|
| 162 |
183 |
}
|
| 163 |
184 |
}
|
|
185 |
if (i >= 0)
|
|
186 |
/* last argument numerical index */
|
|
187 |
goto INDEX_ARG;
|
| 164 |
188 |
|
| 165 |
189 |
/*
|
| 166 |
190 |
* Option validation
|
| ... | ... | |
| 172 |
196 |
|
| 173 |
197 |
ac -= optind;
|
| 174 |
198 |
av += optind;
|
| 175 |
|
flags = 0;
|
| 176 |
199 |
if (ac > 1)
|
| 177 |
200 |
flags |= UNDO_FLAG_MULT;
|
| 178 |
201 |
|
| ... | ... | |
| 215 |
238 |
|
| 216 |
239 |
/*
|
| 217 |
240 |
* Iterate through a file's history. If cmd == CMD_DUMP we take the
|
| 218 |
|
* next-to-last transaction id. Otherwise if cmd == CMD_ITERATEALL
|
| 219 |
|
* we scan all transaction ids.
|
|
241 |
* next-to-last transaction id unless another given. Otherwise if
|
|
242 |
* cmd == CMD_ITERATEALL we scan all transaction ids.
|
| 220 |
243 |
*
|
| 221 |
244 |
* Also iterate through the directory's history to locate other inodes that
|
| 222 |
245 |
* used the particular file name.
|
| ... | ... | |
| 258 |
281 |
}
|
| 259 |
282 |
}
|
| 260 |
283 |
if (cmd == CMD_DUMP) {
|
| 261 |
|
/*
|
| 262 |
|
* Single entry, most recent prior to current
|
| 263 |
|
*/
|
| 264 |
|
if (ts1.tid == 0 && RB_EMPTY(&tse_tree)) {
|
|
284 |
if ((ts1.tid == 0 ||
|
|
285 |
flags & (UNDO_FLAG_SETTID1|UNDO_FLAG_SETTID2)) &&
|
|
286 |
RB_EMPTY(&tse_tree)) {
|
| 265 |
287 |
if ((fd = open(filename, O_RDONLY)) > 0) {
|
| 266 |
288 |
collect_history(fd, &error, &tse_tree);
|
| 267 |
289 |
close(fd);
|
| 268 |
290 |
}
|
| 269 |
291 |
}
|
|
292 |
/*
|
|
293 |
* Find entry if tid set to placeholder index
|
|
294 |
*/
|
|
295 |
if (flags & UNDO_FLAG_SETTID1){
|
|
296 |
tse1 = RB_MAX(undo_hist_entry_rb_tree, &tse_tree);
|
|
297 |
while (tse1 && ts1.tid--)
|
|
298 |
tse1 = RB_PREV(undo_hist_entry_rb_tree,
|
|
299 |
&tse_tree, tse1);
|
|
300 |
if (tse1)
|
|
301 |
ts1 = tse1->tse;
|
|
302 |
else
|
|
303 |
ts1.tid = 0;
|
|
304 |
}
|
|
305 |
if (flags & UNDO_FLAG_SETTID2){
|
|
306 |
tse2 = RB_MAX(undo_hist_entry_rb_tree, &tse_tree);
|
|
307 |
while (tse2 && ts2.tid--)
|
|
308 |
tse2 = RB_PREV(undo_hist_entry_rb_tree,
|
|
309 |
&tse_tree, tse2);
|
|
310 |
if (tse2)
|
|
311 |
ts2 = tse2->tse;
|
|
312 |
else
|
|
313 |
ts2.tid = 0;
|
|
314 |
}
|
|
315 |
/*
|
|
316 |
* Single entry, most recent prior to current
|
|
317 |
*/
|
| 270 |
318 |
if (ts1.tid == 0) {
|
| 271 |
319 |
tse2 = RB_MAX(undo_hist_entry_rb_tree, &tse_tree);
|
| 272 |
320 |
if (tse2) {
|