]> granicus.if.org Git - nethack/commitdiff
SELF_RECOVER for win32
authornethack.allison <nethack.allison>
Wed, 21 Aug 2002 03:30:19 +0000 (03:30 +0000)
committernethack.allison <nethack.allison>
Wed, 21 Aug 2002 03:30:19 +0000 (03:30 +0000)
- define SELF_RECOVER for win32
- add code to perform a recover operation from
  within NetHack itself when SELF_RECOVER is defined

include/extern.h
include/ntconf.h
src/files.c
sys/share/pcunix.c
sys/winnt/winnt.c

index 0914ab464fa412a49efd63b40134f6d653250705..42df9d61ff14652ef4c7365d7358026eec4b79c0 100644 (file)
@@ -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 ### */
index a4cecf427c9a8a5bb1d106599e70bec5274f38e9..840b15c507ff12ab977146daae1dd74ae8a5b70d 100644 (file)
@@ -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 */
 
 /*
  * -----------------------------------------------------------------
index 938be7f82032681a42df7f7948b59d1b8f02d707..5d89e26d822940df32bfe45dc95dcaf05ba7a9d1 100644 (file)
@@ -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*/
index 96d7c58653927e4bafaf942645101280b765b636..7c2b70aab81038cda38e21bdce0c05b357ef88e8 100644 (file)
@@ -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
index 650f3bae44d36d7b0838b5b003cb299f749dbc6a..155c2d059b5fd002981e1f58fb5aeb7cabf00bd7 100644 (file)
@@ -234,6 +234,39 @@ void win32_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 */
 
 /*winnt.c*/