home *** CD-ROM | disk | FTP | other *** search
- /* recover.c - NetHack version 3.1 */
-
- /*
- * 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 <fcntl.h>
- #endif
-
- #ifndef VMS
- # ifdef exit
- # undef exit
- # endif
- #ifdef MICRO
- extern void FDECL(exit, (int));
- #endif
- #else /* 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 FDECL(create_savefile, (char *));
- void FDECL(copy_bytes, (int,int));
-
- #ifdef UNIX
- #define SAVESIZE (PL_NSIZ + 13) /* save/99999player.e */
- #else
- # ifdef VMS
- #define SAVESIZE (PL_NSIZ + 22) /* [.save]<uid>player.e;1 */
- # else
- #define SAVESIZE FILENAME /* from macconf.h or pcconf.h */
- # endif
- #endif
-
- char savename[SAVESIZE]; /* holds relative path of save file from playground */
-
-
- int
- main(argc, argv)
- int argc;
- char *argv[];
- {
- int argno;
- char *dir = (char *)0;
-
- if (argc == 1 || (argc == 2 && !strcmp(argv[1], "-"))) {
- (void) fprintf(stderr,
- "Usage: %s [-d directory] base1 base2 ...\n",
- argv[0]);
- exit(1);
- }
-
- 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) {
- (void) fprintf(stderr,
- "%s: flag -d must be followed by a directory name.\n",
- argv[0]);
- exit(1);
- }
- argno++;
- }
-
- if (!dir) dir = getenv("NETHACKDIR");
- if (!dir) dir = getenv("HACKDIR");
- #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
-
- if (dir && chdir(dir) < 0) {
- (void) fprintf(stderr, "%s: cannot chdir to %s.\n",
- argv[0], dir);
- exit(1);
- }
-
- while (argc > argno) {
- (void) restore_savefile(argv[argno]);
- argno++;
- }
- #ifndef VMS
- return 0;
- #else
- return 1; /* vms success */
- #endif /*VMS*/
- }
-
- static char lock[256];
-
- void
- set_levelfile_name(lev)
- int lev;
- {
- char *tf;
-
- tf = rindex(lock, '.');
- if (!tf) {
- tf = lock;
- while (*tf) tf++;
- }
- #ifdef VMS
- (void) sprintf(tf, ".%d;1", lev);
- #else
- (void) sprintf(tf, ".%d", lev);
- #endif
- }
-
- int
- open_levelfile(lev)
- int lev;
- {
- int fd;
-
- set_levelfile_name(lev);
- #ifdef MICRO
- fd = open(lock, O_RDONLY | O_BINARY);
- #else
- fd = open(lock, O_RDONLY, 0);
- #endif
- return fd;
- }
-
- int
- create_savefile(savename)
- char *savename;
- {
- int fd;
-
- #ifdef MICRO
- 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) {
- (void) fprintf(stderr, "file copy failed!\n");
- exit(1);
- }
- } while (nfrom == BUFSIZ);
- }
-
- int
- restore_savefile(basename)
- char *basename;
- {
- int gfd, lfd, sfd;
- int lev, savelev, hpid;
- xchar levc;
-
- /* 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) {
- (void) fprintf(stderr, "Cannot open level 0 for %s.\n", basename);
- return(-1);
- }
- (void) read(gfd, (genericptr_t) &hpid, sizeof(hpid));
- if (read(gfd, (genericptr_t) &savelev, sizeof(savelev))
- != sizeof(savelev)) {
- (void) fprintf(stderr,
- "Checkpointing was not in effect for %s -- recovery impossible.\n",
- basename);
- (void) close(gfd);
- return(-1);
- }
- (void) read(gfd, (genericptr_t) savename, sizeof(savename));
-
- /* save file should contain:
- * current level (including pets)
- * (non-level-based) game state
- * other levels
- */
- sfd = create_savefile(savename);
- if (sfd < 0) {
- (void) fprintf(stderr, "Cannot create savefile %s.\n", savename);
- (void) close(gfd);
- return(-1);
- }
-
- lfd = open_levelfile(savelev);
- if (lfd < 0) {
- (void) fprintf(stderr, "Cannot open level of save for %s.\n",
- basename);
- (void) close(gfd);
- (void) close(sfd);
- return(-1);
- }
-
- copy_bytes(lfd, sfd);
- (void) close(lfd);
- (void) unlink(lock);
-
- copy_bytes(gfd, sfd);
- (void) 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);
- (void) close(lfd);
- (void) unlink(lock);
- }
- }
- }
-
- (void) close(sfd);
-
- #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;
-
- 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
- return(0);
- }
-
- /*recover.c*/
-