File: rec.c

package info (click to toggle)
jove 4.16-5
  • links: PTS
  • area: main
  • in suites: potato, slink
  • size: 1,804 kB
  • ctags: 2,866
  • sloc: ansic: 27,140; makefile: 401
file content (184 lines) | stat: -rw-r--r-- 4,654 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
/************************************************************************
 * This program is Copyright (C) 1986-1996 by Jonathan Payne.  JOVE is  *
 * provided to you without charge, and with no warranty.  You may give  *
 * away copies of JOVE, including sources, provided that this notice is *
 * included in all the files.                                           *
 ************************************************************************/

#include "jove.h"

#ifdef RECOVER	/* the body is the rest of this file */

#include "fp.h"
#include "sysprocs.h"
#include "rec.h"
#include "fmt.h"
#include "recover.h"

#if !defined(MAC) && !defined(ZTCDOS)
# include <sys/file.h>
#endif

private int	rec_fd = -1;
private char	*recfname;
private File	*rec_out;

#define dmpobj(obj) fputnchar((char *) &obj, (int) sizeof(obj), rec_out)

#ifndef L_SET
# define L_SET 0
#endif

private struct rec_head	Header;

void
rectmpname(tfname)
char *tfname;
{
	if (strlen(tfname) >= sizeof(Header.TmpFileName)) {
		complain("temporary filename too long; recovery disabled.");
		/* NOTREACHED */
	}
	strcpy(Header.TmpFileName, tfname);
}

private void
recinit()
{
	char	buf[FILESIZE];

	swritef(buf, sizeof(buf), "%s/%s", TmpDir,
#ifdef MAC
		".jrecXXX"	/* must match string in mac.c:Ffilter() */
#else
		"jrecXXXXXX"
#endif
		);
	recfname = copystr(buf);
	recfname = mktemp(recfname);
	rec_fd = creat(recfname, 0644);
	if (rec_fd == -1) {
		complain("Cannot create \"%s\"; recovery disabled.", recfname);
		/*NOTREACHED*/
	}
	/* initialize the recovery file */
	rec_out = fd_open(recfname, F_WRITE|F_LOCKED, rec_fd, iobuff, LBSIZE);

	/* Initialize the record header (TmpFileName initialized by rectmpname). */
	Header.RecMagic = RECMAGIC;
#ifdef UNIX
	Header.Uid = getuid();
	Header.Pid = getpid();
#endif
}

/* Close recfile before execing a child process.
 * Since we might be vforking, we must not change any variables
 * (in particular rec_fd).
 */
void
recclose()
{
	if (rec_fd != -1)
		(void) close(rec_fd);
}

/* Close and remove recfile before exiting. */


void
recremove()
{
	if (rec_fd != -1) {
		recclose();
		(void) unlink(recfname);
	}
}

/* Write out the line pointers for buffer B. */

private void
dmppntrs(b)
register Buffer	*b;
{
	register LinePtr	lp;

	for (lp = b->b_first; lp != NULL; lp = lp->l_next)
		dmpobj(lp->l_dline);
}

/* dump the buffer info and then the actual line pointers. */

private void
dmp_buf_header(b)
register Buffer	*b;
{
	struct rec_entry	record;

	byte_zero(&record, sizeof(struct rec_entry));	/* clean out holes for purify */
	record.r_dotline = LinesTo(b->b_first, b->b_dot);
	record.r_dotchar = b->b_char;
	record.r_nlines = record.r_dotline + LinesTo(b->b_dot, (LinePtr)NULL);
	strcpy(record.r_fname, b->b_fname ? b->b_fname : NullStr);
	strcpy(record.r_bname, b->b_name);
	dmpobj(record);
}

/* Goes through all the buffers and syncs them to the disk. */

int	ModCount = 0;	/* number of buffer mods since last sync */

int	SyncFreq = 50;	/* VAR: how often to sync the file pointers */

void
SyncRec()
{
	register Buffer	*b;
	static bool	beenhere = NO;

	/* Count number of interesting buffers.  If none, don't bother syncing. */
	Header.Nbuffers = 0;
	for (b = world; b != NULL; b = b->b_next)
		if (b->b_type != B_SCRATCH && IsModified(b))
			Header.Nbuffers += 1;
	if (Header.Nbuffers == 0)
		return;

	lsave();	/* this makes things really right */
	SyncTmp();	/* note: this will force rectmpname() */

	if (!beenhere) {
		beenhere = YES;
		recinit();	/* Init recover file. */
	}
	/* Note: once writing to the recover file fails, we permanently
	 * stop trying.  This is to avoid useless thrashing.  Perhaps
	 * there should be a way to turn this back on.
	 */
	if (rec_fd == -1 || (rec_out->f_flags & F_ERR))
		return;

	f_seek(rec_out, (off_t)0);
	(void) time(&Header.UpdTime);
	Header.FreePtr = DFree;
	dmpobj(Header);
	for (b = world; b != NULL; b = b->b_next)
		if (b->b_type != B_SCRATCH && IsModified(b))
			dmp_buf_header(b);
	for (b = world; b != NULL; b = b->b_next)
		if (b->b_type != B_SCRATCH && IsModified(b))
			dmppntrs(b);
	flushout(rec_out);
}

/* To be implemented:
   Full Recover.  What we have to do is go find the name of the tmp
   file data/rec pair and use those instead of the ones we would have
   created eventually.  The rec file has a list of buffers, and then
   the actual pointers.  Stored for each buffer is the buffer name,
   the file name, the number of lines, the current line, the current
   character.  The current modes do not need saving as they will be
   saved when the file name is set.  If a process was running in a
   buffer, it will be lost. */

#endif /* RECOVER */