1 /* NetHack 3.6 recover.c $NHDT-Date: 1550103078 2019/02/14 00:11:18 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.19 $ */
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.
16 #if !defined(O_WRONLY) && !defined(LSC) && !defined(AZTEC_C)
19 #if 1 /*JP*//* copy from lint.h */
21 #define PRAGMA_IGNORE_HELPER0(x) #x
22 #define PRAGMA_IGNORE_HELPER1(x) PRAGMA_IGNORE_HELPER0(GCC diagnostic ignored x)
23 #define PRAGMA_IGNORE_HELPER2(y) PRAGMA_IGNORE_HELPER1(#y)
24 #define _pragma_ignore(opt) _Pragma("GCC diagnostic push") \
25 _Pragma(PRAGMA_IGNORE_HELPER2(opt))
26 #define _pragma_pop _Pragma("GCC diagnostic pop")
29 #define _pragma_ignore(opt)
36 extern int FDECL(vms_creat, (const char *, unsigned));
37 extern int FDECL(vms_open, (const char *, int, unsigned));
40 int FDECL(restore_savefile, (char *));
41 void FDECL(set_levelfile_name, (int));
42 int FDECL(open_levelfile, (int));
43 int NDECL(create_savefile);
44 void FDECL(copy_bytes, (int, int));
47 #define Fprintf (void) fprintf
49 #define Fprintf (void) nhce_message
50 static void nhce_message(FILE *, const char *, ...);
53 #define Close (void) close
56 #define SAVESIZE (PL_NSIZ + 13) /* save/99999player.e */
59 #define SAVESIZE (PL_NSIZ + 22) /* [.save]<uid>player.e;1 */
62 #define SAVESIZE (PL_NSIZ + 40) /* username-player.NetHack-saved-game */
64 #define SAVESIZE FILENAME /* from macconf.h or pcconf.h */
70 char *FDECL(exepath, (char *));
73 #if defined(__BORLANDC__) && !defined(_WIN32)
74 extern unsigned _stklen = STKSIZ;
76 char savename[SAVESIZE]; /* holds relative path of save file from playground */
84 const char *dir = (char *) 0;
86 char *startdir = (char *) 0;
90 dir = getenv("NETHACKDIR");
92 dir = getenv("HACKDIR");
95 dir = exepath(argv[0]);
97 if (argc == 1 || (argc == 2 && !strcmp(argv[1], "-"))) {
98 Fprintf(stderr, "Usage: %s [ -d directory ] base1 [ base2 ... ]\n",
100 #if defined(WIN32) || defined(MSDOS)
104 "\t(Unless you override it with -d, recover will look \n");
105 Fprintf(stderr, "\t in the %s directory on your system)\n", dir);
112 if (!strncmp(argv[argno], "-d", 2)) {
113 dir = argv[argno] + 2;
114 if (*dir == '=' || *dir == ':')
116 if (!*dir && argc > argno) {
122 "%s: flag -d must be followed by a directory name.\n",
128 #if defined(SECURE) && !defined(VMS)
131 && strcmp(dir, HACKDIR)
134 _pragma_ignore(-Wunused-result)
135 (void) setgid(getgid());
136 (void) setuid(getuid());
139 #endif /* SECURE && !VMS */
147 startdir = getcwd(0, 255);
149 if (dir && chdir((char *) dir) < 0) {
150 Fprintf(stderr, "%s: cannot chdir to %s.\n", argv[0], dir);
154 while (argc > argno) {
155 if (restore_savefile(argv[argno]) == 0)
156 Fprintf(stderr, "recovered \"%s\" to %s\n", argv[argno],
162 (void) chdir(startdir);
169 static char lock[256];
172 set_levelfile_name(lev)
177 tf = rindex(lock, '.');
179 tf = lock + strlen(lock);
180 (void) sprintf(tf, ".%d", lev);
182 (void) strcat(tf, ";1");
192 set_levelfile_name(lev);
193 #if defined(MICRO) || defined(WIN32) || defined(MSDOS)
194 fd = open(lock, O_RDONLY | O_BINARY);
196 fd = open(lock, O_RDONLY, 0);
206 #if defined(MICRO) || defined(WIN32) || defined(MSDOS)
207 fd = open(savename, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, FCMASK);
209 fd = creat(savename, FCMASK);
222 nfrom = read(ifd, buf, BUFSIZ);
223 nto = write(ofd, buf, nfrom);
225 Fprintf(stderr, "file copy failed!\n");
228 } while (nfrom == BUFSIZ);
232 restore_savefile(basename)
236 int res = 0, lev, savelev, hpid, pltmpsiz;
238 struct version_info version_data;
239 struct savefile_info sfi;
242 /* level 0 file contains:
243 * pid of creating process (ignored here)
244 * level number for current level of save file
245 * name of save file nethack would have created
250 (void) strcpy(lock, basename);
251 gfd = open_levelfile(0);
253 #if defined(WIN32) && !defined(WIN_CE)
254 if (errno == EACCES) {
257 "\nThere are files from a game in progress under your name.");
258 Fprintf(stderr, "\nThe files are locked or inaccessible.");
259 Fprintf(stderr, "\nPerhaps the other game is still running?\n");
261 Fprintf(stderr, "\nTrouble accessing level 0 (errno = %d).\n",
264 Fprintf(stderr, "Cannot open level 0 for %s.\n", basename);
267 if (read(gfd, (genericptr_t) &hpid, sizeof hpid) != sizeof hpid) {
269 stderr, "%s\n%s%s%s\n",
270 "Checkpoint data incompletely written or subsequently clobbered;",
271 "recovery for \"", basename, "\" impossible.");
275 if (read(gfd, (genericptr_t) &savelev, sizeof(savelev))
276 != sizeof(savelev)) {
277 Fprintf(stderr, "Checkpointing was not in effect for %s -- recovery "
283 if ((read(gfd, (genericptr_t) savename, sizeof savename)
285 || (read(gfd, (genericptr_t) &version_data, sizeof version_data)
286 != sizeof version_data)
287 || (read(gfd, (genericptr_t) &sfi, sizeof sfi) != sizeof sfi)
288 || (read(gfd, (genericptr_t) &pltmpsiz, sizeof pltmpsiz)
289 != sizeof pltmpsiz) || (pltmpsiz > PL_NSIZ)
290 || (read(gfd, (genericptr_t) plbuf, pltmpsiz) != pltmpsiz)) {
291 Fprintf(stderr, "Error reading %s -- can't recover.\n", lock);
296 /* save file should contain:
300 * current level (including pets)
301 * (non-level-based) game state
304 sfd = create_savefile();
306 Fprintf(stderr, "Cannot create savefile %s.\n", savename);
311 lfd = open_levelfile(savelev);
313 Fprintf(stderr, "Cannot open level of save for %s.\n", basename);
319 if (write(sfd, (genericptr_t) &version_data, sizeof version_data)
320 != sizeof version_data) {
321 Fprintf(stderr, "Error writing %s; recovery failed.\n", savename);
328 if (write(sfd, (genericptr_t) &sfi, sizeof sfi) != sizeof sfi) {
330 "Error writing %s; recovery failed (savefile_info).\n",
338 if (write(sfd, (genericptr_t) &pltmpsiz, sizeof pltmpsiz)
339 != sizeof pltmpsiz) {
341 "Error writing %s; recovery failed (player name size).\n",
349 if (write(sfd, (genericptr_t) plbuf, pltmpsiz) != pltmpsiz) {
350 Fprintf(stderr, "Error writing %s; recovery failed (player name).\n",
358 copy_bytes(lfd, sfd);
362 copy_bytes(gfd, sfd);
364 set_levelfile_name(0);
367 for (lev = 1; lev < 256 && res == 0; lev++) {
368 /* level numbers are kept in xchars in save.c, so the
369 * maximum level number (for the endlevel) must be < 256
371 if (lev != savelev) {
372 lfd = open_levelfile(lev);
374 /* any or all of these may not exist */
376 if (write(sfd, (genericptr_t) &levc, sizeof levc)
380 copy_bytes(lfd, sfd);
389 #if 0 /* OBSOLETE, HackWB is no longer in use */
392 /* we need to create an icon for the saved game
393 * or HackWB won't notice the file.
395 char iconfile[FILENAME];
398 (void) sprintf(iconfile, "%s.info", savename);
399 in = open("NetHack:default.icon", O_RDONLY);
400 out = open(iconfile, O_WRONLY | O_TRUNC | O_CREAT);
401 if (in > -1 && out > -1) {
416 #define PATH_SEPARATOR '/'
418 #define PATH_SEPARATOR '\\'
421 #define EXEPATHBUFSZ 256
422 char exepathbuf[EXEPATHBUFSZ];
433 bsize = EXEPATHBUFSZ;
440 TCHAR wbuf[EXEPATHBUFSZ];
441 GetModuleFileName((HANDLE) 0, wbuf, EXEPATHBUFSZ);
442 NH_W2A(wbuf, tmp, bsize);
445 *(tmp + GetModuleFileName((HANDLE) 0, tmp, bsize)) = '\0';
448 tmp2 = strrchr(tmp, PATH_SEPARATOR);
457 const char amiga_version_string[] = AMIGA_VERSION_STRING;
462 nhce_message(FILE *f, const char *str, ...)
465 TCHAR wbuf[NHSTR_BUFSIZE];
466 char buf[NHSTR_BUFSIZE];
469 vsprintf(buf, str, ap);
472 MessageBox(NULL, NH_A2W(buf, wbuf, NHSTR_BUFSIZE), TEXT("Recover"),