log4.c revision 1.3.4.2 1 1.3.4.2 yamt /* $NetBSD: log4.c,v 1.3.4.2 2014/05/22 15:50:33 yamt Exp $ */
2 1.3.4.2 yamt /*-
3 1.3.4.2 yamt * Copyright (c) 1992, 1993, 1994
4 1.3.4.2 yamt * The Regents of the University of California. All rights reserved.
5 1.3.4.2 yamt * Copyright (c) 1992, 1993, 1994, 1995, 1996
6 1.3.4.2 yamt * Keith Bostic. All rights reserved.
7 1.3.4.2 yamt *
8 1.3.4.2 yamt * See the LICENSE file for redistribution information.
9 1.3.4.2 yamt */
10 1.3.4.2 yamt
11 1.3.4.2 yamt #include "config.h"
12 1.3.4.2 yamt
13 1.3.4.2 yamt #include <sys/cdefs.h>
14 1.3.4.2 yamt #if 0
15 1.3.4.2 yamt #ifndef lint
16 1.3.4.2 yamt static const char sccsid[] = "Id: log4.c,v 10.3 2002/06/08 21:00:33 skimo Exp ";
17 1.3.4.2 yamt #endif /* not lint */
18 1.3.4.2 yamt #else
19 1.3.4.2 yamt __RCSID("$NetBSD: log4.c,v 1.3.4.2 2014/05/22 15:50:33 yamt Exp $");
20 1.3.4.2 yamt #endif
21 1.3.4.2 yamt
22 1.3.4.2 yamt #include <sys/types.h>
23 1.3.4.2 yamt #include <sys/queue.h>
24 1.3.4.2 yamt #include <sys/stat.h>
25 1.3.4.2 yamt
26 1.3.4.2 yamt #include <bitstring.h>
27 1.3.4.2 yamt #include <errno.h>
28 1.3.4.2 yamt #include <fcntl.h>
29 1.3.4.2 yamt #include <limits.h>
30 1.3.4.2 yamt #include <stdio.h>
31 1.3.4.2 yamt #include <stdlib.h>
32 1.3.4.2 yamt #include <string.h>
33 1.3.4.2 yamt
34 1.3.4.2 yamt #include "common.h"
35 1.3.4.2 yamt
36 1.3.4.2 yamt /*
37 1.3.4.2 yamt * The log consists of records, each containing a type byte and a variable
38 1.3.4.2 yamt * length byte string, as follows:
39 1.3.4.2 yamt *
40 1.3.4.2 yamt * LOG_CURSOR_INIT MARK
41 1.3.4.2 yamt * LOG_CURSOR_END MARK
42 1.3.4.2 yamt * LOG_LINE_APPEND_F db_recno_t char *
43 1.3.4.2 yamt * LOG_LINE_APPEND_B db_recno_t char *
44 1.3.4.2 yamt * LOG_LINE_DELETE_F db_recno_t char *
45 1.3.4.2 yamt * LOG_LINE_DELETE_B db_recno_t char *
46 1.3.4.2 yamt * LOG_LINE_RESET_F db_recno_t char *
47 1.3.4.2 yamt * LOG_LINE_RESET_B db_recno_t char *
48 1.3.4.2 yamt * LOG_MARK LMARK
49 1.3.4.2 yamt *
50 1.3.4.2 yamt * We do before image physical logging. This means that the editor layer
51 1.3.4.2 yamt * MAY NOT modify records in place, even if simply deleting or overwriting
52 1.3.4.2 yamt * characters. Since the smallest unit of logging is a line, we're using
53 1.3.4.2 yamt * up lots of space. This may eventually have to be reduced, probably by
54 1.3.4.2 yamt * doing logical logging, which is a much cooler database phrase.
55 1.3.4.2 yamt *
56 1.3.4.2 yamt * The implementation of the historic vi 'u' command, using roll-forward and
57 1.3.4.2 yamt * roll-back, is simple. Each set of changes has a LOG_CURSOR_INIT record,
58 1.3.4.2 yamt * followed by a number of other records, followed by a LOG_CURSOR_END record.
59 1.3.4.2 yamt * LOG_LINE_RESET records come in pairs. The first is a LOG_LINE_RESET_B
60 1.3.4.2 yamt * record, and is the line before the change. The second is LOG_LINE_RESET_F,
61 1.3.4.2 yamt * and is the line after the change. Roll-back is done by backing up to the
62 1.3.4.2 yamt * first LOG_CURSOR_INIT record before a change. Roll-forward is done in a
63 1.3.4.2 yamt * similar fashion.
64 1.3.4.2 yamt *
65 1.3.4.2 yamt * The 'U' command is implemented by rolling backward to a LOG_CURSOR_END
66 1.3.4.2 yamt * record for a line different from the current one. It should be noted that
67 1.3.4.2 yamt * this means that a subsequent 'u' command will make a change based on the
68 1.3.4.2 yamt * new position of the log's cursor. This is okay, and, in fact, historic vi
69 1.3.4.2 yamt * behaved that way.
70 1.3.4.2 yamt */
71 1.3.4.2 yamt
72 1.3.4.2 yamt static int log_cursor1 __P((SCR *, int));
73 1.3.4.2 yamt
74 1.3.4.2 yamt /*
75 1.3.4.2 yamt * log_init --
76 1.3.4.2 yamt * Initialize the logging subsystem.
77 1.3.4.2 yamt *
78 1.3.4.2 yamt * PUBLIC: int log_init __P((SCR *, EXF *));
79 1.3.4.2 yamt */
80 1.3.4.2 yamt int
81 1.3.4.2 yamt log_init(SCR *sp, EXF *ep)
82 1.3.4.2 yamt {
83 1.3.4.2 yamt DB_LOGC *logc;
84 1.3.4.2 yamt DBT data;
85 1.3.4.2 yamt size_t nlen;
86 1.3.4.2 yamt
87 1.3.4.2 yamt /*
88 1.3.4.2 yamt * !!!
89 1.3.4.2 yamt * ep MAY NOT BE THE SAME AS sp->ep, DON'T USE THE LATTER.
90 1.3.4.2 yamt *
91 1.3.4.2 yamt * Initialize the buffer. The logging subsystem has its own
92 1.3.4.2 yamt * buffers because the global ones are almost by definition
93 1.3.4.2 yamt * going to be in use when the log runs.
94 1.3.4.2 yamt */
95 1.3.4.2 yamt sp->wp->l_lp = NULL;
96 1.3.4.2 yamt sp->wp->l_len = 0;
97 1.3.4.2 yamt ep->l_cursor.lno = 1; /* XXX Any valid recno. */
98 1.3.4.2 yamt ep->l_cursor.cno = 0;
99 1.3.4.2 yamt ep->l_high = ep->l_cur = 1;
100 1.3.4.2 yamt
101 1.3.4.2 yamt if ((sp->db_error = ep->env->log_cursor(ep->env, &logc, 0))
102 1.3.4.2 yamt != 0) {
103 1.3.4.2 yamt msgq(sp, M_DBERR, "env->log_cursor");
104 1.3.4.2 yamt F_SET(ep, F_NOLOG);
105 1.3.4.2 yamt return (1);
106 1.3.4.2 yamt }
107 1.3.4.2 yamt nlen = 1024;
108 1.3.4.2 yamt retry:
109 1.3.4.2 yamt BINC_GOTO(sp, sp->wp->l_lp, sp->wp->l_len, nlen);
110 1.3.4.2 yamt memset(&data, 0, sizeof(data));
111 1.3.4.2 yamt data.data = sp->wp->l_lp;
112 1.3.4.2 yamt data.ulen = sp->wp->l_len;
113 1.3.4.2 yamt data.flags = DB_DBT_USERMEM;
114 1.3.4.2 yamt switch ((sp->db_error =
115 1.3.4.2 yamt logc->get(logc, &ep->lsn_first, &data, DB_LAST))) {
116 1.3.4.2 yamt case ENOMEM:
117 1.3.4.2 yamt nlen = data.size;
118 1.3.4.2 yamt goto retry;
119 1.3.4.2 yamt default:
120 1.3.4.2 yamt alloc_err:
121 1.3.4.2 yamt msgq(sp, M_DBERR, "logc->get");
122 1.3.4.2 yamt F_SET(ep, F_NOLOG);
123 1.3.4.2 yamt return (1);
124 1.3.4.2 yamt case 0:
125 1.3.4.2 yamt ;
126 1.3.4.2 yamt }
127 1.3.4.2 yamt MEMCPY(&ep->lsn_cur, &ep->lsn_first, 1);
128 1.3.4.2 yamt MEMCPY(&ep->lsn_high, &ep->lsn_first, 1);
129 1.3.4.2 yamt logc->close(logc, 0);
130 1.3.4.2 yamt
131 1.3.4.2 yamt ep->l_win = NULL;
132 1.3.4.2 yamt /*LOCK_INIT(sp->wp, ep);*/
133 1.3.4.2 yamt
134 1.3.4.2 yamt return (0);
135 1.3.4.2 yamt }
136 1.3.4.2 yamt
137 1.3.4.2 yamt /*
138 1.3.4.2 yamt * log_end --
139 1.3.4.2 yamt * Close the logging subsystem.
140 1.3.4.2 yamt *
141 1.3.4.2 yamt * PUBLIC: int log_end __P((SCR *, EXF *));
142 1.3.4.2 yamt */
143 1.3.4.2 yamt int
144 1.3.4.2 yamt log_end(SCR *sp, EXF *ep)
145 1.3.4.2 yamt {
146 1.3.4.2 yamt /*
147 1.3.4.2 yamt * !!!
148 1.3.4.2 yamt * ep MAY NOT BE THE SAME AS sp->ep, DON'T USE THE LATTER.
149 1.3.4.2 yamt */
150 1.3.4.2 yamt /*LOCK_END(sp->wp, ep);*/
151 1.3.4.2 yamt if (sp->wp->l_lp != NULL) {
152 1.3.4.2 yamt free(sp->wp->l_lp);
153 1.3.4.2 yamt sp->wp->l_lp = NULL;
154 1.3.4.2 yamt }
155 1.3.4.2 yamt sp->wp->l_len = 0;
156 1.3.4.2 yamt ep->l_cursor.lno = 1; /* XXX Any valid recno. */
157 1.3.4.2 yamt ep->l_cursor.cno = 0;
158 1.3.4.2 yamt ep->l_high = ep->l_cur = 1;
159 1.3.4.2 yamt return (0);
160 1.3.4.2 yamt }
161 1.3.4.2 yamt
162 1.3.4.2 yamt /*
163 1.3.4.2 yamt * log_cursor --
164 1.3.4.2 yamt * Log the current cursor position, starting an event.
165 1.3.4.2 yamt *
166 1.3.4.2 yamt * PUBLIC: int log_cursor __P((SCR *));
167 1.3.4.2 yamt */
168 1.3.4.2 yamt int
169 1.3.4.2 yamt log_cursor(SCR *sp)
170 1.3.4.2 yamt {
171 1.3.4.2 yamt EXF *ep;
172 1.3.4.2 yamt
173 1.3.4.2 yamt ep = sp->ep;
174 1.3.4.2 yamt if (F_ISSET(ep, F_NOLOG))
175 1.3.4.2 yamt return (0);
176 1.3.4.2 yamt
177 1.3.4.2 yamt /*
178 1.3.4.2 yamt * If any changes were made since the last cursor init,
179 1.3.4.2 yamt * put out the ending cursor record.
180 1.3.4.2 yamt */
181 1.3.4.2 yamt if (ep->l_cursor.lno == OOBLNO) {
182 1.3.4.2 yamt if (ep->l_win && ep->l_win != sp->wp)
183 1.3.4.2 yamt return 0;
184 1.3.4.2 yamt ep->l_cursor.lno = sp->lno;
185 1.3.4.2 yamt ep->l_cursor.cno = sp->cno;
186 1.3.4.2 yamt ep->l_win = NULL;
187 1.3.4.2 yamt return (log_cursor1(sp, LOG_CURSOR_END));
188 1.3.4.2 yamt }
189 1.3.4.2 yamt ep->l_cursor.lno = sp->lno;
190 1.3.4.2 yamt ep->l_cursor.cno = sp->cno;
191 1.3.4.2 yamt return (0);
192 1.3.4.2 yamt }
193 1.3.4.2 yamt
194 1.3.4.2 yamt /*
195 1.3.4.2 yamt * log_cursor1 --
196 1.3.4.2 yamt * Actually push a cursor record out.
197 1.3.4.2 yamt */
198 1.3.4.2 yamt static int
199 1.3.4.2 yamt log_cursor1(SCR *sp, int type)
200 1.3.4.2 yamt {
201 1.3.4.2 yamt DBT data, key;
202 1.3.4.2 yamt EXF *ep;
203 1.3.4.2 yamt
204 1.3.4.2 yamt ep = sp->ep;
205 1.3.4.2 yamt
206 1.3.4.2 yamt /*
207 1.3.4.2 yamt if (type == LOG_CURSOR_INIT &&
208 1.3.4.2 yamt LOCK_TRY(sp->wp, ep))
209 1.3.4.2 yamt return 1;
210 1.3.4.2 yamt */
211 1.3.4.2 yamt
212 1.3.4.2 yamt if (type == LOG_CURSOR_INIT &&
213 1.3.4.2 yamt (sp->db_error = __vi_log_truncate(ep)) != 0) {
214 1.3.4.2 yamt msgq(sp, M_DBERR, "truncate");
215 1.3.4.2 yamt return 1;
216 1.3.4.2 yamt }
217 1.3.4.2 yamt if ((sp->db_error =
218 1.3.4.2 yamt __vi_cursor_log(ep->env, NULL, &ep->lsn_cur, 0, type,
219 1.3.4.2 yamt ep->l_cursor.lno, ep->l_cursor.cno)) != 0) {
220 1.3.4.2 yamt msgq(sp, M_DBERR, "cursor_log");
221 1.3.4.2 yamt return 1;
222 1.3.4.2 yamt }
223 1.3.4.2 yamt if (type == LOG_CURSOR_END) {
224 1.3.4.2 yamt MEMCPY(&ep->lsn_high, &ep->lsn_cur, 1);
225 1.3.4.2 yamt /* XXXX should not be needed */
226 1.3.4.2 yamt ep->env->log_flush(ep->env, NULL);
227 1.3.4.2 yamt }
228 1.3.4.2 yamt
229 1.3.4.2 yamt #if defined(DEBUG) && 0
230 1.3.4.2 yamt vtrace(sp, "%lu: %s: %u/%u\n", ep->l_cur,
231 1.3.4.2 yamt type == LOG_CURSOR_INIT ? "log_cursor_init" : "log_cursor_end",
232 1.3.4.2 yamt sp->lno, sp->cno);
233 1.3.4.2 yamt #endif
234 1.3.4.2 yamt /* Reset high water mark. */
235 1.3.4.2 yamt ep->l_high = ++ep->l_cur;
236 1.3.4.2 yamt
237 1.3.4.2 yamt /*
238 1.3.4.2 yamt if (type == LOG_CURSOR_END)
239 1.3.4.2 yamt LOCK_UNLOCK(sp->wp, ep);
240 1.3.4.2 yamt */
241 1.3.4.2 yamt return (0);
242 1.3.4.2 yamt }
243 1.3.4.2 yamt
244 1.3.4.2 yamt /*
245 1.3.4.2 yamt * log_line --
246 1.3.4.2 yamt * Log a line change.
247 1.3.4.2 yamt *
248 1.3.4.2 yamt * PUBLIC: int log_line __P((SCR *, db_recno_t, u_int));
249 1.3.4.2 yamt */
250 1.3.4.2 yamt int
251 1.3.4.2 yamt log_line(SCR *sp, db_recno_t lno, u_int action)
252 1.3.4.2 yamt {
253 1.3.4.2 yamt DBT data, key;
254 1.3.4.2 yamt EXF *ep;
255 1.3.4.2 yamt size_t len;
256 1.3.4.2 yamt CHAR_T *lp;
257 1.3.4.2 yamt db_recno_t lcur;
258 1.3.4.2 yamt
259 1.3.4.2 yamt ep = sp->ep;
260 1.3.4.2 yamt if (F_ISSET(ep, F_NOLOG))
261 1.3.4.2 yamt return (0);
262 1.3.4.2 yamt
263 1.3.4.2 yamt /*
264 1.3.4.2 yamt * XXX
265 1.3.4.2 yamt *
266 1.3.4.2 yamt * Kluge for vi. Clear the EXF undo flag so that the
267 1.3.4.2 yamt * next 'u' command does a roll-back, regardless.
268 1.3.4.2 yamt */
269 1.3.4.2 yamt F_CLR(ep, F_UNDO);
270 1.3.4.2 yamt
271 1.3.4.2 yamt /* Put out one initial cursor record per set of changes. */
272 1.3.4.2 yamt if (ep->l_cursor.lno != OOBLNO) {
273 1.3.4.2 yamt if (log_cursor1(sp, LOG_CURSOR_INIT))
274 1.3.4.2 yamt return (1);
275 1.3.4.2 yamt ep->l_cursor.lno = OOBLNO;
276 1.3.4.2 yamt ep->l_win = sp->wp;
277 1.3.4.2 yamt } /*else if (ep->l_win != sp->wp) {
278 1.3.4.2 yamt printf("log_line own: %p, this: %p\n", ep->l_win, sp->wp);
279 1.3.4.2 yamt return 1;
280 1.3.4.2 yamt }*/
281 1.3.4.2 yamt
282 1.3.4.2 yamt if ((sp->db_error =
283 1.3.4.2 yamt __vi_change_log(ep->env, NULL, &ep->lsn_cur, 0, action,
284 1.3.4.2 yamt lno)) != 0) {
285 1.3.4.2 yamt msgq(sp, M_DBERR, "change_log");
286 1.3.4.2 yamt return 1;
287 1.3.4.2 yamt }
288 1.3.4.2 yamt
289 1.3.4.2 yamt #if defined(DEBUG) && 0
290 1.3.4.2 yamt switch (action) {
291 1.3.4.2 yamt case LOG_LINE_APPEND_F:
292 1.3.4.2 yamt vtrace(sp, "%u: log_line: append_f: %lu {%u}\n",
293 1.3.4.2 yamt ep->l_cur, lno, len);
294 1.3.4.2 yamt break;
295 1.3.4.2 yamt case LOG_LINE_APPEND_B:
296 1.3.4.2 yamt vtrace(sp, "%u: log_line: append_b: %lu {%u}\n",
297 1.3.4.2 yamt ep->l_cur, lno, len);
298 1.3.4.2 yamt break;
299 1.3.4.2 yamt case LOG_LINE_DELETE_F:
300 1.3.4.2 yamt vtrace(sp, "%lu: log_line: delete_f: %lu {%u}\n",
301 1.3.4.2 yamt ep->l_cur, lno, len);
302 1.3.4.2 yamt break;
303 1.3.4.2 yamt case LOG_LINE_DELETE_B:
304 1.3.4.2 yamt vtrace(sp, "%lu: log_line: delete_b: %lu {%u}\n",
305 1.3.4.2 yamt ep->l_cur, lno, len);
306 1.3.4.2 yamt break;
307 1.3.4.2 yamt case LOG_LINE_RESET_F:
308 1.3.4.2 yamt vtrace(sp, "%lu: log_line: reset_f: %lu {%u}\n",
309 1.3.4.2 yamt ep->l_cur, lno, len);
310 1.3.4.2 yamt break;
311 1.3.4.2 yamt case LOG_LINE_RESET_B:
312 1.3.4.2 yamt vtrace(sp, "%lu: log_line: reset_b: %lu {%u}\n",
313 1.3.4.2 yamt ep->l_cur, lno, len);
314 1.3.4.2 yamt break;
315 1.3.4.2 yamt }
316 1.3.4.2 yamt #endif
317 1.3.4.2 yamt /* Reset high water mark. */
318 1.3.4.2 yamt ep->l_high = ++ep->l_cur;
319 1.3.4.2 yamt
320 1.3.4.2 yamt return (0);
321 1.3.4.2 yamt }
322 1.3.4.2 yamt
323 1.3.4.2 yamt /*
324 1.3.4.2 yamt * log_mark --
325 1.3.4.2 yamt * Log a mark position. For the log to work, we assume that there
326 1.3.4.2 yamt * aren't any operations that just put out a log record -- this
327 1.3.4.2 yamt * would mean that undo operations would only reset marks, and not
328 1.3.4.2 yamt * cause any other change.
329 1.3.4.2 yamt *
330 1.3.4.2 yamt * PUBLIC: int log_mark __P((SCR *, LMARK *));
331 1.3.4.2 yamt */
332 1.3.4.2 yamt int
333 1.3.4.2 yamt log_mark(SCR *sp, LMARK *lmp)
334 1.3.4.2 yamt {
335 1.3.4.2 yamt DBT data, key;
336 1.3.4.2 yamt EXF *ep;
337 1.3.4.2 yamt
338 1.3.4.2 yamt ep = sp->ep;
339 1.3.4.2 yamt if (F_ISSET(ep, F_NOLOG))
340 1.3.4.2 yamt return (0);
341 1.3.4.2 yamt
342 1.3.4.2 yamt /* Put out one initial cursor record per set of changes. */
343 1.3.4.2 yamt if (ep->l_cursor.lno != OOBLNO) {
344 1.3.4.2 yamt if (log_cursor1(sp, LOG_CURSOR_INIT))
345 1.3.4.2 yamt return (1);
346 1.3.4.2 yamt ep->l_cursor.lno = OOBLNO;
347 1.3.4.2 yamt ep->l_win = sp->wp;
348 1.3.4.2 yamt }
349 1.3.4.2 yamt
350 1.3.4.2 yamt if ((sp->db_error =
351 1.3.4.2 yamt __vi_mark_log(ep->env, NULL, &ep->lsn_cur, 0,
352 1.3.4.2 yamt lmp)) != 0) {
353 1.3.4.2 yamt msgq(sp, M_DBERR, "cursor_log");
354 1.3.4.2 yamt return 1;
355 1.3.4.2 yamt }
356 1.3.4.2 yamt
357 1.3.4.2 yamt #if defined(DEBUG) && 0
358 1.3.4.2 yamt vtrace(sp, "%lu: mark %c: %lu/%u\n",
359 1.3.4.2 yamt ep->l_cur, lmp->name, lmp->lno, lmp->cno);
360 1.3.4.2 yamt #endif
361 1.3.4.2 yamt /* Reset high water mark. */
362 1.3.4.2 yamt ep->l_high = ++ep->l_cur;
363 1.3.4.2 yamt return (0);
364 1.3.4.2 yamt }
365 1.3.4.2 yamt
366 1.3.4.2 yamt /*
367 1.3.4.2 yamt * Log_backward --
368 1.3.4.2 yamt * Roll the log backward one operation.
369 1.3.4.2 yamt *
370 1.3.4.2 yamt * PUBLIC: int log_backward __P((SCR *, MARK *));
371 1.3.4.2 yamt */
372 1.3.4.2 yamt int
373 1.3.4.2 yamt log_backward(SCR *sp, MARK *rp)
374 1.3.4.2 yamt {
375 1.3.4.2 yamt EXF *ep;
376 1.3.4.2 yamt LMARK lm;
377 1.3.4.2 yamt MARK m;
378 1.3.4.2 yamt db_recno_t lno;
379 1.3.4.2 yamt int didop;
380 1.3.4.2 yamt u_char *p;
381 1.3.4.2 yamt size_t size;
382 1.3.4.2 yamt
383 1.3.4.2 yamt ep = sp->ep;
384 1.3.4.2 yamt if (F_ISSET(ep, F_NOLOG)) {
385 1.3.4.2 yamt msgq(sp, M_ERR,
386 1.3.4.2 yamt "010|Logging not being performed, undo not possible");
387 1.3.4.2 yamt return (1);
388 1.3.4.2 yamt }
389 1.3.4.2 yamt
390 1.3.4.2 yamt if (log_compare(&ep->lsn_cur, &ep->lsn_first) <= 0) {
391 1.3.4.2 yamt msgq(sp, M_BERR, "011|No changes to undo");
392 1.3.4.2 yamt return (1);
393 1.3.4.2 yamt }
394 1.3.4.2 yamt return __vi_log_traverse(sp, UNDO_BACKWARD, rp);
395 1.3.4.2 yamt }
396 1.3.4.2 yamt
397 1.3.4.2 yamt /*
398 1.3.4.2 yamt * Log_setline --
399 1.3.4.2 yamt * Reset the line to its original appearance.
400 1.3.4.2 yamt *
401 1.3.4.2 yamt * XXX
402 1.3.4.2 yamt * There's a bug in this code due to our not logging cursor movements
403 1.3.4.2 yamt * unless a change was made. If you do a change, move off the line,
404 1.3.4.2 yamt * then move back on and do a 'U', the line will be restored to the way
405 1.3.4.2 yamt * it was before the original change.
406 1.3.4.2 yamt *
407 1.3.4.2 yamt * PUBLIC: int log_setline __P((SCR *));
408 1.3.4.2 yamt */
409 1.3.4.2 yamt int
410 1.3.4.2 yamt log_setline(SCR *sp)
411 1.3.4.2 yamt {
412 1.3.4.2 yamt EXF *ep;
413 1.3.4.2 yamt LMARK lm;
414 1.3.4.2 yamt MARK m;
415 1.3.4.2 yamt db_recno_t lno;
416 1.3.4.2 yamt u_char *p;
417 1.3.4.2 yamt size_t size;
418 1.3.4.2 yamt
419 1.3.4.2 yamt ep = sp->ep;
420 1.3.4.2 yamt if (F_ISSET(ep, F_NOLOG)) {
421 1.3.4.2 yamt msgq(sp, M_ERR,
422 1.3.4.2 yamt "012|Logging not being performed, undo not possible");
423 1.3.4.2 yamt return (1);
424 1.3.4.2 yamt }
425 1.3.4.2 yamt
426 1.3.4.2 yamt if (log_compare(&ep->lsn_cur, &ep->lsn_first) <= 0) {
427 1.3.4.2 yamt msgq(sp, M_BERR, "011|No changes to undo");
428 1.3.4.2 yamt return (1);
429 1.3.4.2 yamt }
430 1.3.4.2 yamt return __vi_log_traverse(sp, UNDO_SETLINE, &m);
431 1.3.4.2 yamt }
432 1.3.4.2 yamt
433 1.3.4.2 yamt /*
434 1.3.4.2 yamt * Log_forward --
435 1.3.4.2 yamt * Roll the log forward one operation.
436 1.3.4.2 yamt *
437 1.3.4.2 yamt * PUBLIC: int log_forward __P((SCR *, MARK *));
438 1.3.4.2 yamt */
439 1.3.4.2 yamt int
440 1.3.4.2 yamt log_forward(SCR *sp, MARK *rp)
441 1.3.4.2 yamt {
442 1.3.4.2 yamt EXF *ep;
443 1.3.4.2 yamt LMARK lm;
444 1.3.4.2 yamt MARK m;
445 1.3.4.2 yamt db_recno_t lno;
446 1.3.4.2 yamt int didop;
447 1.3.4.2 yamt u_char *p;
448 1.3.4.2 yamt size_t size;
449 1.3.4.2 yamt
450 1.3.4.2 yamt ep = sp->ep;
451 1.3.4.2 yamt if (F_ISSET(ep, F_NOLOG)) {
452 1.3.4.2 yamt msgq(sp, M_ERR,
453 1.3.4.2 yamt "013|Logging not being performed, roll-forward not possible");
454 1.3.4.2 yamt return (1);
455 1.3.4.2 yamt }
456 1.3.4.2 yamt
457 1.3.4.2 yamt if (log_compare(&ep->lsn_cur, &ep->lsn_high) >= 0) {
458 1.3.4.2 yamt msgq(sp, M_BERR, "014|No changes to re-do");
459 1.3.4.2 yamt return (1);
460 1.3.4.2 yamt }
461 1.3.4.2 yamt return __vi_log_traverse(sp, UNDO_FORWARD, rp);
462 1.3.4.2 yamt }
463