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 */
|