⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 recover.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 2 页
字号:
/*- * Copyright (c) 1993, 1994 *	The Regents of the University of California.  All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *	This product includes software developed by the University of *	California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#ifndef lintstatic char sccsid[] = "@(#)recover.c	8.51 (Berkeley) 3/25/94";#endif /* not lint */#include <sys/param.h>#include <sys/queue.h>#include <sys/stat.h>#include <sys/time.h>/* * We include <sys/file.h>, because the flock(2) #defines were * found there on historical systems.  We also include <fcntl.h> * because the open(2) #defines are found there on newer systems. */#include <sys/file.h>#include <netdb.h>		/* MAXHOSTNAMELEN on some systems. */#include <bitstring.h>#include <dirent.h>#include <errno.h>#include <fcntl.h>#include <limits.h>#include <pwd.h>#include <signal.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <termios.h>#include <unistd.h>#include "compat.h"#include <db.h>#include <regex.h>#include <pathnames.h>#include "vi.h"/* * Recovery code. * * The basic scheme is there's a btree file, whose name we specify.  The first * time a file is modified, and then at RCV_PERIOD intervals after that, the * btree file is synced to disk.  Each time a keystroke is requested for a file * the terminal routines check to see if the file needs to be synced.  This, of * course means that the data structures had better be consistent each time the * key routines are called. * * We don't use timers other than to flag that the file should be synced.  This * would require that the SCR and EXF data structures be locked, the dbopen(3) * routines lock out the timers for each update, etc.  It's just not worth it. * The only way we can lose in the current scheme is if the file is saved, then * the user types furiously for RCV_PERIOD - 1 seconds, and types nothing more. * Not likely. * * When a file is first modified, a file which can be handed off to the mailer * is created.  The file contains normal headers, with two additions, which * occur in THIS order, as the FIRST TWO headers: * *	Vi-recover-file: file_name *	Vi-recover-path: recover_path * * Since newlines delimit the headers, this means that file names cannot * have newlines in them, but that's probably okay. * * Btree files are named "vi.XXXX" and recovery files are named "recover.XXXX". */#define	VI_FHEADER	"Vi-recover-file: "#define	VI_PHEADER	"Vi-recover-path: "static int	rcv_mailfile __P((SCR *, EXF *));static void	rcv_syncit __P((SCR *, int));/* * rcv_tmp -- *	Build a file name that will be used as the recovery file. */intrcv_tmp(sp, ep, name)	SCR *sp;	EXF *ep;	char *name;{	struct stat sb;	int fd;	char *dp, *p, path[MAXPATHLEN];	/*	 * If the recovery directory doesn't exist, try and create it.  As	 * the recovery files are themselves protected from reading/writing	 * by other than the owner, the worst that can happen is that a user	 * would have permission to remove other users recovery files.  If	 * the sticky bit has the BSD semantics, that too will be impossible.	 */	dp = O_STR(sp, O_RECDIR);	if (stat(dp, &sb)) {		if (errno != ENOENT || mkdir(dp, 0)) {			msgq(sp, M_ERR, "Error: %s: %s", dp, strerror(errno));			goto err;		}		(void)chmod(dp, S_IRWXU | S_IRWXG | S_IRWXO | S_ISVTX);	}	/* Newlines delimit the mail messages. */	for (p = name; *p; ++p)		if (*p == '\n') {			msgq(sp, M_ERR,		    "Files with newlines in the name are unrecoverable.");			goto err;		}	(void)snprintf(path, sizeof(path), "%s/vi.XXXXXX", dp);	/*	 * !!!	 * We depend on mkstemp(3) setting the permissions correctly.	 * For GP's, we do it ourselves, to keep the window as small	 * as possible.	 */	if ((fd = mkstemp(path)) == -1) {		msgq(sp, M_ERR, "Error: %s: %s", dp, strerror(errno));		goto err;	}	(void)chmod(path, S_IRUSR | S_IWUSR);	(void)close(fd);	if ((ep->rcv_path = strdup(path)) == NULL) {		msgq(sp, M_SYSERR, NULL);		(void)unlink(path);err:		msgq(sp, M_ERR,		    "Modifications not recoverable if the session fails.");		return (1);	}	/* We believe the file is recoverable. */	F_SET(ep, F_RCV_ON);	return (0);}/* * rcv_init -- *	Force the file to be snapshotted for recovery. */intrcv_init(sp, ep)	SCR *sp;	EXF *ep;{	recno_t lno;	int btear;	/* Only do this once. */	F_CLR(ep, F_FIRSTMODIFY);	/* If we already know the file isn't recoverable, we're done. */	if (!F_ISSET(ep, F_RCV_ON))		return (0);	/* Turn off recoverability until we figure out if this will work. */	F_CLR(ep, F_RCV_ON);	/* If not recovering a file, build a file to mail to the user. */	if (ep->rcv_mpath == NULL && rcv_mailfile(sp, ep))		goto err;	/* Force read of entire file. */	if (file_lline(sp, ep, &lno))		goto err;	/* Turn on a busy message, and sync it to backing store. */	btear = F_ISSET(sp, S_EXSILENT) ? 0 :	    !busy_on(sp, "Copying file for recovery...");	if (ep->db->sync(ep->db, R_RECNOSYNC)) {		msgq(sp, M_ERR, "Preservation failed: %s: %s",		    ep->rcv_path, strerror(errno));		if (btear)			busy_off(sp);		goto err;	}	if (btear)		busy_off(sp);	if (!F_ISSET(sp->gp, G_RECOVER_SET) && rcv_on(sp, ep)) {err:		msgq(sp, M_ERR,		    "Modifications not recoverable if the session fails.");		return (1);	}	/* We believe the file is recoverable. */	F_SET(ep, F_RCV_ON);	return (0);}/* * rcv_mailfile -- *	Build the file to mail to the user. */static intrcv_mailfile(sp, ep)	SCR *sp;	EXF *ep;{	struct passwd *pw;	uid_t uid;	FILE *fp;	time_t now;	int fd;	char *p, *t, host[MAXHOSTNAMELEN], path[MAXPATHLEN];	if ((pw = getpwuid(uid = getuid())) == NULL) {		msgq(sp, M_ERR, "Information on user id %u not found.", uid);		return (1);	}	(void)snprintf(path, sizeof(path),	    "%s/recover.XXXXXX", O_STR(sp, O_RECDIR));	if ((fd = mkstemp(path)) == -1 || (fp = fdopen(fd, "w")) == NULL) {		msgq(sp, M_ERR,		    "Error: %s: %s", O_STR(sp, O_RECDIR), strerror(errno));		if (fd != -1)			(void)close(fd);		return (1);	}	/*	 * We keep an open lock on the file so that the recover option can	 * distinguish between files that are live and those that need to	 * be recovered.  There's an obvious window between the mkstemp call	 * and the lock, but it's pretty small.	 */	if ((ep->rcv_fd = dup(fd)) == -1 ||	    flock(ep->rcv_fd, LOCK_EX | LOCK_NB))		msgq(sp, M_SYSERR, "Unable to lock recovery file");	if ((ep->rcv_mpath = strdup(path)) == NULL) {		msgq(sp, M_SYSERR, NULL);		(void)fclose(fp);		return (1);	}	t = FILENAME(sp->frp);	if ((p = strrchr(t, '/')) == NULL)		p = t;	else		++p;	(void)time(&now);	(void)gethostname(host, sizeof(host));	(void)fprintf(fp, "%s%s\n%s%s\n%s\n%s\n%s%s\n%s%s\n%s\n\n",	    VI_FHEADER, p,			/* Non-standard. */	    VI_PHEADER, ep->rcv_path,		/* Non-standard. */	    "Reply-To: root",	    "From: root (Nvi recovery program)",	    "To: ", pw->pw_name,	    "Subject: Nvi saved the file ", p,	    "Precedence: bulk");			/* For vacation(1). */	(void)fprintf(fp, "%s%.24s%s%s\n%s%s",	    "On ", ctime(&now),	    ", the user ", pw->pw_name,	    "was editing a file named ", p);	if (p != t)		(void)fprintf(fp, " (%s)", t);	(void)fprintf(fp, "\n%s%s%s\n",	    "on the machine ", host, ", when it was saved for\nrecovery.");	(void)fprintf(fp, "\n%s\n%s\n%s\n\n",	    "You can recover most, if not all, of the changes",	    "to this file using the -l and -r options to nvi(1)",	    "or nex(1).");	if (fflush(fp) || ferror(fp)) {		msgq(sp, M_SYSERR, NULL);		(void)fclose(fp);		return (1);	}	(void)fclose(fp);	return (0);}/* * rcv_sync -- *	Sync the backing file. */intrcv_sync(sp, ep)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -