From: jwalz Date: Sat, 5 Jan 2002 21:06:00 +0000 (+0000) Subject: *** empty log message *** X-Git-Tag: MOVE2GIT~3621 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=298ca70e704def554cef5402fb30b793472273b1;p=nethack *** empty log message *** --- diff --git a/util/recover.c b/util/recover.c new file mode 100644 index 000000000..94ab54763 --- /dev/null +++ b/util/recover.c @@ -0,0 +1,359 @@ +/* SCCS Id: @(#)recover.c 3.3 99/10/23 */ +/* Copyright (c) Janet Walz, 1992. */ +/* NetHack may be freely redistributed. See license for details. */ + +/* + * Utility for reconstructing NetHack save file from a set of individual + * level files. Requires that the `checkpoint' option be enabled at the + * time NetHack creates those level files. + */ +#include "config.h" +#if !defined(O_WRONLY) && !defined(LSC) && !defined(AZTEC_C) +#include +#endif +#ifdef WIN32 +#include "win32api.h" +#endif + +#ifdef VMS +extern int FDECL(vms_creat, (const char *,unsigned)); +extern int FDECL(vms_open, (const char *,int,unsigned)); +#endif /* VMS */ + +int FDECL(restore_savefile, (char *)); +void FDECL(set_levelfile_name, (int)); +int FDECL(open_levelfile, (int)); +int NDECL(create_savefile); +void FDECL(copy_bytes, (int,int)); + +#define Fprintf (void)fprintf +#define Close (void)close + +#ifdef UNIX +#define SAVESIZE (PL_NSIZ + 13) /* save/99999player.e */ +#else +# ifdef VMS +#define SAVESIZE (PL_NSIZ + 22) /* [.save]player.e;1 */ +# else +# ifdef WIN32 +#define SAVESIZE (PL_NSIZ + 40) /* username-player.NetHack-saved-game */ +# else +#define SAVESIZE FILENAME /* from macconf.h or pcconf.h */ +# endif +# endif +#endif + +#if defined(EXEPATH) +char *FDECL(exepath, (char *)); +#endif + +#if defined(__BORLANDC__) && !defined(_WIN32) +extern unsigned _stklen = STKSIZ; +#endif +char savename[SAVESIZE]; /* holds relative path of save file from playground */ + + +int +main(argc, argv) +int argc; +char *argv[]; +{ + int argno; + const char *dir = (char *)0; +#ifdef AMIGA + char *startdir = (char *)0; +#endif + + + if (!dir) dir = getenv("NETHACKDIR"); + if (!dir) dir = getenv("HACKDIR"); +#if defined(EXEPATH) + if (!dir) dir = exepath(argv[0]); +#endif + if (argc == 1 || (argc == 2 && !strcmp(argv[1], "-"))) { + Fprintf(stderr, + "Usage: %s [ -d directory ] base1 [ base2 ... ]\n", argv[0]); +#if defined(WIN32) || defined(MSDOS) + if (dir) { + Fprintf(stderr, "\t(Unless you override it with -d, recover will look \n"); + Fprintf(stderr, "\t in the %s directory on your system)\n", dir); + } +#endif + exit(EXIT_FAILURE); + } + + argno = 1; + if (!strncmp(argv[argno], "-d", 2)) { + dir = argv[argno]+2; + if (*dir == '=' || *dir == ':') dir++; + if (!*dir && argc > argno) { + argno++; + dir = argv[argno]; + } + if (!*dir) { + Fprintf(stderr, + "%s: flag -d must be followed by a directory name.\n", + argv[0]); + exit(EXIT_FAILURE); + } + argno++; + } +#if defined(SECURE) && !defined(VMS) + if (dir +# ifdef HACKDIR + && strcmp(dir, HACKDIR) +# endif + ) { + (void) setgid(getgid()); + (void) setuid(getuid()); + } +#endif /* SECURE && !VMS */ + +#ifdef HACKDIR + if (!dir) dir = HACKDIR; +#endif + +#ifdef AMIGA + startdir = getcwd(0,255); +#endif + if (dir && chdir((char *) dir) < 0) { + Fprintf(stderr, "%s: cannot chdir to %s.\n", argv[0], dir); + exit(EXIT_FAILURE); + } + + while (argc > argno) { + if (restore_savefile(argv[argno]) == 0) + Fprintf(stderr, "recovered \"%s\" to %s\n", + argv[argno], savename); + argno++; + } +#ifdef AMIGA + if (startdir) (void)chdir(startdir); +#endif + exit(EXIT_SUCCESS); + /*NOTREACHED*/ + return 0; +} + +static char lock[256]; + +void +set_levelfile_name(lev) +int lev; +{ + char *tf; + + tf = rindex(lock, '.'); + if (!tf) tf = lock + strlen(lock); + (void) sprintf(tf, ".%d", lev); +#ifdef VMS + (void) strcat(tf, ";1"); +#endif +} + +int +open_levelfile(lev) +int lev; +{ + int fd; + + set_levelfile_name(lev); +#if defined(MICRO) || defined(WIN32) || defined(MSDOS) + fd = open(lock, O_RDONLY | O_BINARY); +#else + fd = open(lock, O_RDONLY, 0); +#endif + return fd; +} + +int +create_savefile() +{ + int fd; + +#if defined(MICRO) || defined(WIN32) || defined(MSDOS) + fd = open(savename, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, FCMASK); +#else + fd = creat(savename, FCMASK); +#endif + return fd; +} + +void +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) { + Fprintf(stderr, "file copy failed!\n"); + exit(EXIT_FAILURE); + } + } while (nfrom == BUFSIZ); +} + +int +restore_savefile(basename) +char *basename; +{ + int gfd, lfd, sfd; + int lev, savelev, hpid; + xchar levc; + struct version_info version_data; + + /* 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 + */ + (void) strcpy(lock, basename); + gfd = open_levelfile(0); + if (gfd < 0) { + Fprintf(stderr, "Cannot open level 0 for %s.\n", basename); + return(-1); + } + if (read(gfd, (genericptr_t) &hpid, sizeof hpid) != sizeof hpid) { + Fprintf(stderr, "%s\n%s%s%s\n", + "Checkpoint data incompletely written or subsequently clobbered;", + "recovery for \"", basename, "\" impossible."); + Close(gfd); + return(-1); + } + if (read(gfd, (genericptr_t) &savelev, sizeof(savelev)) + != sizeof(savelev)) { + Fprintf(stderr, + "Checkpointing was not in effect for %s -- recovery impossible.\n", + basename); + Close(gfd); + return(-1); + } + if ((read(gfd, (genericptr_t) savename, sizeof savename) + != sizeof savename) || + (read(gfd, (genericptr_t) &version_data, sizeof version_data) + != sizeof version_data)) { + Fprintf(stderr, "Error reading %s -- can't recover.\n", lock); + Close(gfd); + return(-1); + } + + /* save file should contain: + * version info + * current level (including pets) + * (non-level-based) game state + * other levels + */ + sfd = create_savefile(); + if (sfd < 0) { + Fprintf(stderr, "Cannot create savefile %s.\n", savename); + Close(gfd); + return(-1); + } + + lfd = open_levelfile(savelev); + if (lfd < 0) { + Fprintf(stderr, "Cannot open level of save for %s.\n", basename); + Close(gfd); + Close(sfd); + return(-1); + } + + if (write(sfd, (genericptr_t) &version_data, sizeof version_data) + != sizeof version_data) { + Fprintf(stderr, "Error writing %s; recovery failed.\n", savename); + Close(gfd); + Close(sfd); + return(-1); + } + + copy_bytes(lfd, sfd); + Close(lfd); + (void) unlink(lock); + + copy_bytes(gfd, sfd); + Close(gfd); + set_levelfile_name(0); + (void) unlink(lock); + + 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)); + copy_bytes(lfd, sfd); + Close(lfd); + (void) unlink(lock); + } + } + } + + Close(sfd); + +#if 0 /* OBSOLETE, HackWB is no longer in use */ +#ifdef AMIGA + /* we need to create an icon for the saved game + * or HackWB won't notice the file. + */ + { + char iconfile[FILENAME]; + int in, out; + + (void) sprintf(iconfile, "%s.info", savename); + in = open("NetHack:default.icon", O_RDONLY); + out = open(iconfile, O_WRONLY | O_TRUNC | O_CREAT); + if(in > -1 && out > -1){ + copy_bytes(in,out); + } + if(in > -1)close(in); + if(out > -1)close(out); + } +#endif +#endif + return(0); +} + +#ifdef EXEPATH +# ifdef __DJGPP__ +#define PATH_SEPARATOR '/' +# else +#define PATH_SEPARATOR '\\' +# endif + +#define EXEPATHBUFSZ 256 +char exepathbuf[EXEPATHBUFSZ]; + +char *exepath(str) +char *str; +{ + char *tmp, *tmp2; + int bsize; + + if (!str) return (char *)0; + bsize = EXEPATHBUFSZ; + tmp = exepathbuf; +# ifndef WIN32 + strcpy (tmp, str); +# else + *(tmp + GetModuleFileName((HANDLE)0, tmp, bsize)) = '\0'; +# endif + tmp2 = strrchr(tmp, PATH_SEPARATOR); + if (tmp2) *tmp2 = '\0'; + return tmp; +} +#endif /* EXEPATH */ + +#ifdef AMIGA +#include "date.h" +const char amiga_version_string[] = AMIGA_VERSION_STRING; +#endif + +/*recover.c*/