SELF_RECOVER for win32
- define SELF_RECOVER for win32 - add code to perform a recover operation from within NetHack itself when SELF_RECOVER is defined
This commit is contained in:
@@ -644,6 +644,9 @@ E void FDECL(paniclog, (const char *, const char *));
|
|||||||
E int FDECL(validate_prefix_locations, (char *));
|
E int FDECL(validate_prefix_locations, (char *));
|
||||||
E char** NDECL(get_saved_games);
|
E char** NDECL(get_saved_games);
|
||||||
E void FDECL(free_saved_games, (char**));
|
E void FDECL(free_saved_games, (char**));
|
||||||
|
#ifdef SELF_RECOVER
|
||||||
|
E boolean NDECL(recover_savefile);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* ### fountain.c ### */
|
/* ### fountain.c ### */
|
||||||
|
|
||||||
@@ -1233,8 +1236,10 @@ E char *FDECL(get_username, (int *));
|
|||||||
E void FDECL(nt_regularize, (char *));
|
E void FDECL(nt_regularize, (char *));
|
||||||
E int NDECL((*nt_kbhit));
|
E int NDECL((*nt_kbhit));
|
||||||
E void FDECL(Delay, (int));
|
E void FDECL(Delay, (int));
|
||||||
|
# if !defined(WIN_CE)
|
||||||
|
E boolean FDECL(is_NetHack_process, (int));
|
||||||
|
# endif /* !WIN_CE */
|
||||||
# endif /* WIN32 */
|
# endif /* WIN32 */
|
||||||
|
|
||||||
#endif /* MICRO || WIN32 */
|
#endif /* MICRO || WIN32 */
|
||||||
|
|
||||||
/* ### mthrowu.c ### */
|
/* ### mthrowu.c ### */
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#define PC_LOCKING /* Prevent overwrites of aborted or in-progress games */
|
#define PC_LOCKING /* Prevent overwrites of aborted or in-progress games */
|
||||||
/* without first receiving confirmation. */
|
/* without first receiving confirmation. */
|
||||||
|
|
||||||
|
#define SELF_RECOVER /* Allow the game itself to recover from an aborted game */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* -----------------------------------------------------------------
|
* -----------------------------------------------------------------
|
||||||
|
|||||||
166
src/files.c
166
src/files.c
@@ -132,6 +132,9 @@ int FDECL(parse_config_line, (FILE *,char *,char *,char *));
|
|||||||
#ifdef NOCWD_ASSUMPTIONS
|
#ifdef NOCWD_ASSUMPTIONS
|
||||||
STATIC_DCL void FDECL(adjust_prefix, (char *, int));
|
STATIC_DCL void FDECL(adjust_prefix, (char *, int));
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef SELF_RECOVER
|
||||||
|
STATIC_DCL boolean FDECL(copy_bytes, (int, int));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -2083,4 +2086,167 @@ const char* s;
|
|||||||
|
|
||||||
/* ---------- END PANIC/IMPOSSIBLE LOG ----------- */
|
/* ---------- END PANIC/IMPOSSIBLE LOG ----------- */
|
||||||
|
|
||||||
|
#ifdef SELF_RECOVER
|
||||||
|
|
||||||
|
/* ---------- BEGIN INTERNAL RECOVER ----------- */
|
||||||
|
boolean
|
||||||
|
recover_savefile()
|
||||||
|
{
|
||||||
|
int gfd, lfd, sfd;
|
||||||
|
int lev, savelev, hpid;
|
||||||
|
xchar levc;
|
||||||
|
struct version_info version_data;
|
||||||
|
int processed[256];
|
||||||
|
char savename[SAVESIZE];
|
||||||
|
|
||||||
|
for (lev = 0; lev < 256; lev++)
|
||||||
|
processed[lev] = 0;
|
||||||
|
|
||||||
|
/* level 0 file contains:
|
||||||
|
* pid of creating process (ignored here)
|
||||||
|
* level number for current level of save file
|
||||||
|
* name of save file nethack would have created
|
||||||
|
* and game state
|
||||||
|
*/
|
||||||
|
gfd = open_levelfile(0);
|
||||||
|
if (gfd < 0) {
|
||||||
|
raw_printf("Cannot open level 0 for %s.\n", lock);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
if (read(gfd, (genericptr_t) &hpid, sizeof hpid) != sizeof hpid) {
|
||||||
|
raw_printf(
|
||||||
|
"\nCheckpoint data incompletely written or subsequently clobbered. Recovery impossible.");
|
||||||
|
(void)close(gfd);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
#if defined(WIN32) && !defined(WIN_CE)
|
||||||
|
if (is_NetHack_process(hpid)) {
|
||||||
|
raw_printf(
|
||||||
|
"\nThe level files belong to an active NetHack process and cannot be recovered.");
|
||||||
|
(void)close(gfd);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (read(gfd, (genericptr_t) &savelev, sizeof(savelev))
|
||||||
|
!= sizeof(savelev)) {
|
||||||
|
raw_printf("\nCheckpointing was not in effect for %s -- recovery impossible.\n",
|
||||||
|
lock);
|
||||||
|
(void)close(gfd);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
if ((read(gfd, (genericptr_t) savename, sizeof savename)
|
||||||
|
!= sizeof savename) ||
|
||||||
|
(read(gfd, (genericptr_t) &version_data, sizeof version_data)
|
||||||
|
!= sizeof version_data)) {
|
||||||
|
raw_printf("\nError reading %s -- can't recover.\n", lock);
|
||||||
|
(void)close(gfd);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* save file should contain:
|
||||||
|
* version info
|
||||||
|
* current level (including pets)
|
||||||
|
* (non-level-based) game state
|
||||||
|
* other levels
|
||||||
|
*/
|
||||||
|
set_savefile_name();
|
||||||
|
sfd = create_savefile();
|
||||||
|
if (sfd < 0) {
|
||||||
|
raw_printf("\nCannot recover savefile %s.\n", SAVEF);
|
||||||
|
(void)close(gfd);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
lfd = open_levelfile(savelev);
|
||||||
|
if (lfd < 0) {
|
||||||
|
raw_printf("\nCannot open level of save for %s.\n", lock);
|
||||||
|
(void)close(gfd);
|
||||||
|
(void)close(sfd);
|
||||||
|
delete_savefile();
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (write(sfd, (genericptr_t) &version_data, sizeof version_data)
|
||||||
|
!= sizeof version_data) {
|
||||||
|
raw_printf("\nError writing %s; recovery failed.", SAVEF);
|
||||||
|
(void)close(gfd);
|
||||||
|
(void)close(sfd);
|
||||||
|
delete_savefile();
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!copy_bytes(lfd, sfd)) {
|
||||||
|
(void) close(lfd);
|
||||||
|
(void) close(sfd);
|
||||||
|
delete_savefile();
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
(void)close(lfd);
|
||||||
|
processed[savelev] = 1;
|
||||||
|
|
||||||
|
if (!copy_bytes(gfd, sfd)) {
|
||||||
|
(void) close(lfd);
|
||||||
|
(void) close(sfd);
|
||||||
|
delete_savefile();
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
(void)close(gfd);
|
||||||
|
processed[0] = 1;
|
||||||
|
|
||||||
|
for (lev = 1; lev < 256; lev++) {
|
||||||
|
/* level numbers are kept in xchars in save.c, so the
|
||||||
|
* maximum level number (for the endlevel) must be < 256
|
||||||
|
*/
|
||||||
|
if (lev != savelev) {
|
||||||
|
lfd = open_levelfile(lev);
|
||||||
|
if (lfd >= 0) {
|
||||||
|
/* any or all of these may not exist */
|
||||||
|
levc = (xchar) lev;
|
||||||
|
write(sfd, (genericptr_t) &levc, sizeof(levc));
|
||||||
|
if (!copy_bytes(lfd, sfd)) {
|
||||||
|
(void) close(lfd);
|
||||||
|
(void) close(sfd);
|
||||||
|
delete_savefile();
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
(void)close(lfd);
|
||||||
|
processed[lev] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(void)close(sfd);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We have a successful savefile!
|
||||||
|
* Only now do we erase the level files.
|
||||||
|
*/
|
||||||
|
for (lev = 0; lev < 256; lev++) {
|
||||||
|
if (processed[lev]) {
|
||||||
|
const char *fq_lock;
|
||||||
|
set_levelfile_name(lock, lev);
|
||||||
|
fq_lock = fqname(lock, LEVELPREFIX, 3);
|
||||||
|
(void) unlink(fq_lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean
|
||||||
|
copy_bytes(ifd, ofd)
|
||||||
|
int ifd, ofd;
|
||||||
|
{
|
||||||
|
char buf[BUFSIZ];
|
||||||
|
int nfrom, nto;
|
||||||
|
|
||||||
|
do {
|
||||||
|
nfrom = read(ifd, buf, BUFSIZ);
|
||||||
|
nto = write(ofd, buf, nfrom);
|
||||||
|
if (nto != nfrom) return FALSE;
|
||||||
|
} while (nfrom == BUFSIZ);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------- END INTERNAL RECOVER ----------- */
|
||||||
|
#endif /*SELF_RECOVER*/
|
||||||
|
|
||||||
/*files.c*/
|
/*files.c*/
|
||||||
|
|||||||
@@ -106,9 +106,9 @@ getlock()
|
|||||||
/* we ignore QUIT and INT at this point */
|
/* we ignore QUIT and INT at this point */
|
||||||
if (!lock_file(HLOCK, LOCKPREFIX, 10)) {
|
if (!lock_file(HLOCK, LOCKPREFIX, 10)) {
|
||||||
wait_synch();
|
wait_synch();
|
||||||
#if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS)
|
# if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS)
|
||||||
chdirx(orgdir, 0);
|
chdirx(orgdir, 0);
|
||||||
#endif
|
# endif
|
||||||
error("Quitting.");
|
error("Quitting.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,15 +118,15 @@ getlock()
|
|||||||
fq_lock = fqname(lock, LEVELPREFIX, 1);
|
fq_lock = fqname(lock, LEVELPREFIX, 1);
|
||||||
if((fd = open(fq_lock,0)) == -1) {
|
if((fd = open(fq_lock,0)) == -1) {
|
||||||
if(errno == ENOENT) goto gotlock; /* no such file */
|
if(errno == ENOENT) goto gotlock; /* no such file */
|
||||||
#if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS)
|
# if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS)
|
||||||
chdirx(orgdir, 0);
|
chdirx(orgdir, 0);
|
||||||
#endif
|
# endif
|
||||||
#if defined(WIN32)
|
# if defined(WIN32)
|
||||||
error("Bad directory or name: %s\n%s\n",
|
error("Bad directory or name: %s\n%s\n",
|
||||||
fq_lock, strerror(errno));
|
fq_lock, strerror(errno));
|
||||||
#else
|
# else
|
||||||
perror(fq_lock);
|
perror(fq_lock);
|
||||||
#endif
|
# endif
|
||||||
unlock_file(HLOCK);
|
unlock_file(HLOCK);
|
||||||
error("Cannot open %s", fq_lock);
|
error("Cannot open %s", fq_lock);
|
||||||
}
|
}
|
||||||
@@ -134,9 +134,13 @@ getlock()
|
|||||||
(void) close(fd);
|
(void) close(fd);
|
||||||
|
|
||||||
if(iflags.window_inited) {
|
if(iflags.window_inited) {
|
||||||
|
# ifdef SELF_RECOVER
|
||||||
|
c = yn("There are files from a game in progress under your name. Recover?");
|
||||||
|
# else
|
||||||
pline("There is already a game in progress under your name.");
|
pline("There is already a game in progress under your name.");
|
||||||
pline("You may be able to use \"recover %s\" to get it back.\n",tbuf);
|
pline("You may be able to use \"recover %s\" to get it back.\n",tbuf);
|
||||||
c = yn("Do you want to destroy the old game?");
|
c = yn("Do you want to destroy the old game?");
|
||||||
|
# endif
|
||||||
} else {
|
} else {
|
||||||
# if defined(MSDOS) && defined(NO_TERMS)
|
# if defined(MSDOS) && defined(NO_TERMS)
|
||||||
grmode = iflags.grmode;
|
grmode = iflags.grmode;
|
||||||
@@ -144,10 +148,15 @@ getlock()
|
|||||||
# endif
|
# endif
|
||||||
c = 'n';
|
c = 'n';
|
||||||
ct = 0;
|
ct = 0;
|
||||||
|
# ifdef SELF_RECOVER
|
||||||
|
msmsg(
|
||||||
|
"There are files from a game in progress under your name. Recover? [yn]");
|
||||||
|
# else
|
||||||
msmsg("\nThere is already a game in progress under your name.\n");
|
msmsg("\nThere is already a game in progress under your name.\n");
|
||||||
msmsg("If this is unexpected, you may be able to use \n");
|
msmsg("If this is unexpected, you may be able to use \n");
|
||||||
msmsg("\"recover %s\" to get it back.",tbuf);
|
msmsg("\"recover %s\" to get it back.",tbuf);
|
||||||
msmsg("\nDo you want to destroy the old game? [yn] ");
|
msmsg("\nDo you want to destroy the old game? [yn] ");
|
||||||
|
# endif
|
||||||
while ((ci=nhgetch()) != '\n') {
|
while ((ci=nhgetch()) != '\n') {
|
||||||
if (ct > 0) {
|
if (ct > 0) {
|
||||||
# if defined(WIN32CON)
|
# if defined(WIN32CON)
|
||||||
@@ -166,23 +175,38 @@ getlock()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(c == 'y' || c == 'Y')
|
if(c == 'y' || c == 'Y')
|
||||||
|
# ifndef SELF_RECOVER
|
||||||
if(eraseoldlocks()) {
|
if(eraseoldlocks()) {
|
||||||
# if defined(WIN32CON)
|
# if defined(WIN32CON)
|
||||||
clear_screen(); /* display gets fouled up otherwise */
|
clear_screen(); /* display gets fouled up otherwise */
|
||||||
# endif
|
# endif
|
||||||
goto gotlock;
|
goto gotlock;
|
||||||
} else {
|
} else {
|
||||||
unlock_file(HLOCK);
|
unlock_file(HLOCK);
|
||||||
#if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS)
|
# if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS)
|
||||||
chdirx(orgdir, 0);
|
chdirx(orgdir, 0);
|
||||||
#endif
|
# endif
|
||||||
error("Couldn't destroy old game.");
|
error("Couldn't destroy old game.");
|
||||||
}
|
}
|
||||||
|
# else /*SELF_RECOVER*/
|
||||||
|
if(recover_savefile()) {
|
||||||
|
# if defined(WIN32CON)
|
||||||
|
clear_screen(); /* display gets fouled up otherwise */
|
||||||
|
# endif
|
||||||
|
goto gotlock;
|
||||||
|
} else {
|
||||||
|
unlock_file(HLOCK);
|
||||||
|
# if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS)
|
||||||
|
chdirx(orgdir, 0);
|
||||||
|
# endif
|
||||||
|
error("Couldn't recover old game.");
|
||||||
|
}
|
||||||
|
# endif /*SELF_RECOVER*/
|
||||||
else {
|
else {
|
||||||
unlock_file(HLOCK);
|
unlock_file(HLOCK);
|
||||||
#if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS)
|
# if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS)
|
||||||
chdirx(orgdir, 0);
|
chdirx(orgdir, 0);
|
||||||
#endif
|
# endif
|
||||||
error("%s", "");
|
error("%s", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,28 +215,28 @@ gotlock:
|
|||||||
if (fd == -1) ern = errno;
|
if (fd == -1) ern = errno;
|
||||||
unlock_file(HLOCK);
|
unlock_file(HLOCK);
|
||||||
if(fd == -1) {
|
if(fd == -1) {
|
||||||
#if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS)
|
# if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS)
|
||||||
chdirx(orgdir, 0);
|
chdirx(orgdir, 0);
|
||||||
#endif
|
# endif
|
||||||
#if defined(WIN32)
|
# if defined(WIN32)
|
||||||
error("cannot creat file (%s.)\n%s\n%s\"%s\" exists?\n",
|
error("cannot creat file (%s.)\n%s\n%s\"%s\" exists?\n",
|
||||||
fq_lock, strerror(ern), " Are you sure that the directory",
|
fq_lock, strerror(ern), " Are you sure that the directory",
|
||||||
fqn_prefix[LEVELPREFIX]);
|
fqn_prefix[LEVELPREFIX]);
|
||||||
#else
|
# else
|
||||||
error("cannot creat file (%s.)", fq_lock);
|
error("cannot creat file (%s.)", fq_lock);
|
||||||
#endif
|
# endif
|
||||||
} else {
|
} else {
|
||||||
if(write(fd, (char *) &hackpid, sizeof(hackpid))
|
if(write(fd, (char *) &hackpid, sizeof(hackpid))
|
||||||
!= sizeof(hackpid)){
|
!= sizeof(hackpid)){
|
||||||
#if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS)
|
# if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS)
|
||||||
chdirx(orgdir, 0);
|
chdirx(orgdir, 0);
|
||||||
#endif
|
# endif
|
||||||
error("cannot write lock (%s)", fq_lock);
|
error("cannot write lock (%s)", fq_lock);
|
||||||
}
|
}
|
||||||
if(close(fd) == -1) {
|
if(close(fd) == -1) {
|
||||||
#if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS)
|
# if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS)
|
||||||
chdirx(orgdir, 0);
|
chdirx(orgdir, 0);
|
||||||
#endif
|
# endif
|
||||||
error("cannot close lock (%s)", fq_lock);
|
error("cannot close lock (%s)", fq_lock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -220,7 +244,7 @@ gotlock:
|
|||||||
if (grmode) gr_init();
|
if (grmode) gr_init();
|
||||||
# endif
|
# endif
|
||||||
}
|
}
|
||||||
# endif /* PC_LOCKING */
|
#endif /* PC_LOCKING */
|
||||||
|
|
||||||
# ifndef WIN32
|
# ifndef WIN32
|
||||||
void
|
void
|
||||||
|
|||||||
@@ -234,6 +234,39 @@ void win32_abort()
|
|||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !defined(WIN_CE)
|
||||||
|
#include <tlhelp32.h>
|
||||||
|
boolean
|
||||||
|
is_NetHack_process(pid)
|
||||||
|
int pid;
|
||||||
|
{
|
||||||
|
HANDLE hProcessSnap = NULL;
|
||||||
|
PROCESSENTRY32 pe32 = {0};
|
||||||
|
boolean bRet = FALSE;
|
||||||
|
|
||||||
|
hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||||
|
if (hProcessSnap == INVALID_HANDLE_VALUE)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* Set size of the processentry32 structure before using it. */
|
||||||
|
pe32.dwSize = sizeof(PROCESSENTRY32);
|
||||||
|
if (Process32First(hProcessSnap, &pe32)) {
|
||||||
|
do {
|
||||||
|
if (pe32.th32ProcessID == (unsigned)pid && pe32.szExeFile &&
|
||||||
|
((strlen(pe32.szExeFile) >= 12 &&
|
||||||
|
!strcmpi(&pe32.szExeFile[strlen(pe32.szExeFile) - 12], "nethackw.exe")) ||
|
||||||
|
(strlen(pe32.szExeFile) >= 11 &&
|
||||||
|
!strcmpi(&pe32.szExeFile[strlen(pe32.szExeFile) - 11], "nethack.exe"))))
|
||||||
|
bRet = TRUE;
|
||||||
|
}
|
||||||
|
while (Process32Next(hProcessSnap, &pe32));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
bRet = FALSE;
|
||||||
|
CloseHandle(hProcessSnap);
|
||||||
|
return bRet;
|
||||||
|
}
|
||||||
|
#endif /* WIN_CE*/
|
||||||
#endif /* WIN32 */
|
#endif /* WIN32 */
|
||||||
|
|
||||||
/*winnt.c*/
|
/*winnt.c*/
|
||||||
|
|||||||
Reference in New Issue
Block a user