1 /* NetHack 3.6 recover.c $NHDT-Date: 1432512785 2015/05/25 00:13:05 $ $NHDT-Branch: master $:$NHDT-Revision: 1.15 $ */
2 /* Copyright (c) Janet Walz, 1992. */
3 /* NetHack may be freely redistributed. See license for details. */
6 * Utility for reconstructing NetHack save file from a set of individual
7 * level files. Requires that the `checkpoint' option be enabled at the
8 * time NetHack creates those level files.
11 #if !defined(O_WRONLY) && !defined(LSC) && !defined(AZTEC_C)
20 extern int FDECL(vms_creat
, (const char *, unsigned));
21 extern int FDECL(vms_open
, (const char *, int, unsigned));
24 int FDECL(restore_savefile
, (char *));
25 void FDECL(set_levelfile_name
, (int));
26 int FDECL(open_levelfile
, (int));
27 int NDECL(create_savefile
);
28 void FDECL(copy_bytes
, (int, int));
31 #define Fprintf (void) fprintf
33 #define Fprintf (void) nhce_message
34 static void nhce_message(FILE *, const char *, ...);
37 #define Close (void) close
40 #define SAVESIZE (PL_NSIZ + 13) /* save/99999player.e */
43 #define SAVESIZE (PL_NSIZ + 22) /* [.save]<uid>player.e;1 */
46 #define SAVESIZE (PL_NSIZ + 40) /* username-player.NetHack-saved-game */
48 #define SAVESIZE FILENAME /* from macconf.h or pcconf.h */
54 char *FDECL(exepath
, (char *));
57 #if defined(__BORLANDC__) && !defined(_WIN32)
58 extern unsigned _stklen
= STKSIZ
;
61 savename
[SAVESIZE
]; /* holds relative path of save file from playground */
69 const char *dir
= (char *) 0;
71 char *startdir
= (char *) 0;
75 dir
= getenv("NETHACKDIR");
77 dir
= getenv("HACKDIR");
80 dir
= exepath(argv
[0]);
82 if (argc
== 1 || (argc
== 2 && !strcmp(argv
[1], "-"))) {
83 Fprintf(stderr
, "Usage: %s [ -d directory ] base1 [ base2 ... ]\n",
85 #if defined(WIN32) || defined(MSDOS)
89 "\t(Unless you override it with -d, recover will look \n");
90 Fprintf(stderr
, "\t in the %s directory on your system)\n", dir
);
97 if (!strncmp(argv
[argno
], "-d", 2)) {
98 dir
= argv
[argno
] + 2;
99 if (*dir
== '=' || *dir
== ':')
101 if (!*dir
&& argc
> argno
) {
107 "%s: flag -d must be followed by a directory name.\n",
113 #if defined(SECURE) && !defined(VMS)
116 && strcmp(dir
, HACKDIR
)
119 (void) setgid(getgid());
120 (void) setuid(getuid());
122 #endif /* SECURE && !VMS */
130 startdir
= getcwd(0, 255);
132 if (dir
&& chdir((char *) dir
) < 0) {
133 Fprintf(stderr
, "%s: cannot chdir to %s.\n", argv
[0], dir
);
137 while (argc
> argno
) {
138 if (restore_savefile(argv
[argno
]) == 0)
139 Fprintf(stderr
, "recovered \"%s\" to %s\n", argv
[argno
],
145 (void) chdir(startdir
);
152 static char lock
[256];
155 set_levelfile_name(lev
)
160 tf
= rindex(lock
, '.');
162 tf
= lock
+ strlen(lock
);
163 (void) sprintf(tf
, ".%d", lev
);
165 (void) strcat(tf
, ";1");
175 set_levelfile_name(lev
);
176 #if defined(MICRO) || defined(WIN32) || defined(MSDOS)
177 fd
= open(lock
, O_RDONLY
| O_BINARY
);
179 fd
= open(lock
, O_RDONLY
, 0);
189 #if defined(MICRO) || defined(WIN32) || defined(MSDOS)
190 fd
= open(savename
, O_WRONLY
| O_BINARY
| O_CREAT
| O_TRUNC
, FCMASK
);
192 fd
= creat(savename
, FCMASK
);
205 nfrom
= read(ifd
, buf
, BUFSIZ
);
206 nto
= write(ofd
, buf
, nfrom
);
208 Fprintf(stderr
, "file copy failed!\n");
211 } while (nfrom
== BUFSIZ
);
215 restore_savefile(basename
)
219 int lev
, savelev
, hpid
, pltmpsiz
;
221 struct version_info version_data
;
222 struct savefile_info sfi
;
225 /* level 0 file contains:
226 * pid of creating process (ignored here)
227 * level number for current level of save file
228 * name of save file nethack would have created
233 (void) strcpy(lock
, basename
);
234 gfd
= open_levelfile(0);
236 #if defined(WIN32) && !defined(WIN_CE)
237 if (errno
== EACCES
) {
240 "\nThere are files from a game in progress under your name.");
241 Fprintf(stderr
, "\nThe files are locked or inaccessible.");
242 Fprintf(stderr
, "\nPerhaps the other game is still running?\n");
244 Fprintf(stderr
, "\nTrouble accessing level 0 (errno = %d).\n",
247 Fprintf(stderr
, "Cannot open level 0 for %s.\n", basename
);
250 if (read(gfd
, (genericptr_t
) &hpid
, sizeof hpid
) != sizeof hpid
) {
252 stderr
, "%s\n%s%s%s\n",
253 "Checkpoint data incompletely written or subsequently clobbered;",
254 "recovery for \"", basename
, "\" impossible.");
258 if (read(gfd
, (genericptr_t
) &savelev
, sizeof(savelev
))
259 != sizeof(savelev
)) {
260 Fprintf(stderr
, "Checkpointing was not in effect for %s -- recovery "
266 if ((read(gfd
, (genericptr_t
) savename
, sizeof savename
)
268 || (read(gfd
, (genericptr_t
) &version_data
, sizeof version_data
)
269 != sizeof version_data
)
270 || (read(gfd
, (genericptr_t
) &sfi
, sizeof sfi
) != sizeof sfi
)
271 || (read(gfd
, (genericptr_t
) &pltmpsiz
, sizeof pltmpsiz
)
272 != sizeof pltmpsiz
) || (pltmpsiz
> PL_NSIZ
)
273 || (read(gfd
, (genericptr_t
) &plbuf
, pltmpsiz
) != pltmpsiz
)) {
274 Fprintf(stderr
, "Error reading %s -- can't recover.\n", lock
);
279 /* save file should contain:
283 * current level (including pets)
284 * (non-level-based) game state
287 sfd
= create_savefile();
289 Fprintf(stderr
, "Cannot create savefile %s.\n", savename
);
294 lfd
= open_levelfile(savelev
);
296 Fprintf(stderr
, "Cannot open level of save for %s.\n", basename
);
302 if (write(sfd
, (genericptr_t
) &version_data
, sizeof version_data
)
303 != sizeof version_data
) {
304 Fprintf(stderr
, "Error writing %s; recovery failed.\n", savename
);
310 if (write(sfd
, (genericptr_t
) &sfi
, sizeof sfi
) != sizeof sfi
) {
312 "Error writing %s; recovery failed (savefile_info).\n",
319 if (write(sfd
, (genericptr_t
) &pltmpsiz
, sizeof pltmpsiz
)
320 != sizeof pltmpsiz
) {
322 "Error writing %s; recovery failed (player name size).\n",
329 if (write(sfd
, (genericptr_t
) &plbuf
, pltmpsiz
) != pltmpsiz
) {
330 Fprintf(stderr
, "Error writing %s; recovery failed (player name).\n",
337 copy_bytes(lfd
, sfd
);
341 copy_bytes(gfd
, sfd
);
343 set_levelfile_name(0);
346 for (lev
= 1; lev
< 256; lev
++) {
347 /* level numbers are kept in xchars in save.c, so the
348 * maximum level number (for the endlevel) must be < 256
350 if (lev
!= savelev
) {
351 lfd
= open_levelfile(lev
);
353 /* any or all of these may not exist */
355 write(sfd
, (genericptr_t
) &levc
, sizeof(levc
));
356 copy_bytes(lfd
, sfd
);
365 #if 0 /* OBSOLETE, HackWB is no longer in use */
367 /* we need to create an icon for the saved game
368 * or HackWB won't notice the file.
371 char iconfile
[FILENAME
];
374 (void) sprintf(iconfile
, "%s.info", savename
);
375 in
= open("NetHack:default.icon", O_RDONLY
);
376 out
= open(iconfile
, O_WRONLY
| O_TRUNC
| O_CREAT
);
377 if(in
> -1 && out
> -1){
380 if(in
> -1)close(in
);
381 if(out
> -1)close(out
);
390 #define PATH_SEPARATOR '/'
392 #define PATH_SEPARATOR '\\'
395 #define EXEPATHBUFSZ 256
396 char exepathbuf
[EXEPATHBUFSZ
];
407 bsize
= EXEPATHBUFSZ
;
414 TCHAR wbuf
[EXEPATHBUFSZ
];
415 GetModuleFileName((HANDLE
) 0, wbuf
, EXEPATHBUFSZ
);
416 NH_W2A(wbuf
, tmp
, bsize
);
419 *(tmp
+ GetModuleFileName((HANDLE
) 0, tmp
, bsize
)) = '\0';
422 tmp2
= strrchr(tmp
, PATH_SEPARATOR
);
431 const char amiga_version_string
[] = AMIGA_VERSION_STRING
;
436 nhce_message(FILE *f
, const char *str
, ...)
439 TCHAR wbuf
[NHSTR_BUFSIZE
];
440 char buf
[NHSTR_BUFSIZE
];
443 vsprintf(buf
, str
, ap
);
446 MessageBox(NULL
, NH_A2W(buf
, wbuf
, NHSTR_BUFSIZE
), TEXT("Recover"),