From: nethack.allison Date: Wed, 21 Aug 2002 03:30:19 +0000 (+0000) Subject: SELF_RECOVER for win32 X-Git-Tag: MOVE2GIT~2491 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3515dcf1f1fe5e9a68cbcd81d51206f4f23d7933;p=nethack 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 --- diff --git a/include/extern.h b/include/extern.h index 0914ab464..42df9d61f 100644 --- a/include/extern.h +++ b/include/extern.h @@ -644,6 +644,9 @@ E void FDECL(paniclog, (const char *, const char *)); E int FDECL(validate_prefix_locations, (char *)); E char** NDECL(get_saved_games); E void FDECL(free_saved_games, (char**)); +#ifdef SELF_RECOVER +E boolean NDECL(recover_savefile); +#endif /* ### fountain.c ### */ @@ -1233,8 +1236,10 @@ E char *FDECL(get_username, (int *)); E void FDECL(nt_regularize, (char *)); E int NDECL((*nt_kbhit)); E void FDECL(Delay, (int)); +# if !defined(WIN_CE) +E boolean FDECL(is_NetHack_process, (int)); +# endif /* !WIN_CE */ # endif /* WIN32 */ - #endif /* MICRO || WIN32 */ /* ### mthrowu.c ### */ diff --git a/include/ntconf.h b/include/ntconf.h index a4cecf427..840b15c50 100644 --- a/include/ntconf.h +++ b/include/ntconf.h @@ -19,6 +19,7 @@ #define PC_LOCKING /* Prevent overwrites of aborted or in-progress games */ /* without first receiving confirmation. */ +#define SELF_RECOVER /* Allow the game itself to recover from an aborted game */ /* * ----------------------------------------------------------------- diff --git a/src/files.c b/src/files.c index 938be7f82..5d89e26d8 100644 --- a/src/files.c +++ b/src/files.c @@ -132,6 +132,9 @@ int FDECL(parse_config_line, (FILE *,char *,char *,char *)); #ifdef NOCWD_ASSUMPTIONS STATIC_DCL void FDECL(adjust_prefix, (char *, int)); #endif +#ifdef SELF_RECOVER +STATIC_DCL boolean FDECL(copy_bytes, (int, int)); +#endif /* @@ -2083,4 +2086,167 @@ const char* s; /* ---------- 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*/ diff --git a/sys/share/pcunix.c b/sys/share/pcunix.c index 96d7c5865..7c2b70aab 100644 --- a/sys/share/pcunix.c +++ b/sys/share/pcunix.c @@ -106,9 +106,9 @@ getlock() /* we ignore QUIT and INT at this point */ if (!lock_file(HLOCK, LOCKPREFIX, 10)) { wait_synch(); -#if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS) +# if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS) chdirx(orgdir, 0); -#endif +# endif error("Quitting."); } @@ -118,15 +118,15 @@ getlock() fq_lock = fqname(lock, LEVELPREFIX, 1); if((fd = open(fq_lock,0)) == -1) { if(errno == ENOENT) goto gotlock; /* no such file */ -#if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS) +# if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS) chdirx(orgdir, 0); -#endif -#if defined(WIN32) +# endif +# if defined(WIN32) error("Bad directory or name: %s\n%s\n", fq_lock, strerror(errno)); -#else +# else perror(fq_lock); -#endif +# endif unlock_file(HLOCK); error("Cannot open %s", fq_lock); } @@ -134,9 +134,13 @@ getlock() (void) close(fd); 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("You may be able to use \"recover %s\" to get it back.\n",tbuf); c = yn("Do you want to destroy the old game?"); +# endif } else { # if defined(MSDOS) && defined(NO_TERMS) grmode = iflags.grmode; @@ -144,10 +148,15 @@ getlock() # endif c = 'n'; 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("If this is unexpected, you may be able to use \n"); msmsg("\"recover %s\" to get it back.",tbuf); msmsg("\nDo you want to destroy the old game? [yn] "); +# endif while ((ci=nhgetch()) != '\n') { if (ct > 0) { # if defined(WIN32CON) @@ -166,23 +175,38 @@ getlock() } } if(c == 'y' || c == 'Y') +# ifndef SELF_RECOVER if(eraseoldlocks()) { -# if defined(WIN32CON) +# if defined(WIN32CON) clear_screen(); /* display gets fouled up otherwise */ -# endif +# endif goto gotlock; } else { unlock_file(HLOCK); -#if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS) +# if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS) chdirx(orgdir, 0); -#endif +# endif 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 { unlock_file(HLOCK); -#if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS) +# if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS) chdirx(orgdir, 0); -#endif +# endif error("%s", ""); } @@ -191,28 +215,28 @@ gotlock: if (fd == -1) ern = errno; unlock_file(HLOCK); if(fd == -1) { -#if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS) +# if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS) chdirx(orgdir, 0); -#endif -#if defined(WIN32) +# endif +# if defined(WIN32) error("cannot creat file (%s.)\n%s\n%s\"%s\" exists?\n", fq_lock, strerror(ern), " Are you sure that the directory", fqn_prefix[LEVELPREFIX]); -#else +# else error("cannot creat file (%s.)", fq_lock); -#endif +# endif } else { if(write(fd, (char *) &hackpid, sizeof(hackpid)) != sizeof(hackpid)){ -#if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS) +# if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS) chdirx(orgdir, 0); -#endif +# endif error("cannot write lock (%s)", fq_lock); } if(close(fd) == -1) { -#if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS) +# if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS) chdirx(orgdir, 0); -#endif +# endif error("cannot close lock (%s)", fq_lock); } } @@ -220,7 +244,7 @@ gotlock: if (grmode) gr_init(); # endif } -# endif /* PC_LOCKING */ +#endif /* PC_LOCKING */ # ifndef WIN32 void diff --git a/sys/winnt/winnt.c b/sys/winnt/winnt.c index 650f3bae4..155c2d059 100644 --- a/sys/winnt/winnt.c +++ b/sys/winnt/winnt.c @@ -234,6 +234,39 @@ void win32_abort() abort(); } +#if !defined(WIN_CE) +#include +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 */ /*winnt.c*/