NHDT->ANH, nethack->anethack, nhdat->anhdat
[aNetHack.git] / util / recover.c
blob7e1da3fa92efc6999c9345d1abc8a6894c9e8fa7
1 /* aNetHack 0.0.1 recover.c $ANH-Date: 1432512785 2015/05/25 00:13:05 $ $ANH-Branch: master $:$ANH-Revision: 1.15 $ */
2 /* Copyright (c) Janet Walz, 1992. */
3 /* aNetHack may be freely redistributed. See license for details. */
5 /*
6 * Utility for reconstructing aNetHack save file from a set of individual
7 * level files. Requires that the `checkpoint' option be enabled at the
8 * time aNetHack creates those level files.
9 */
10 #include "config.h"
11 #if !defined(O_WRONLY) && !defined(LSC) && !defined(AZTEC_C)
12 #include <fcntl.h>
13 #endif
14 #ifdef WIN32
15 #include <errno.h>
16 #include "win32api.h"
17 #endif
19 #ifdef VMS
20 extern int FDECL(vms_creat, (const char *, unsigned));
21 extern int FDECL(vms_open, (const char *, int, unsigned));
22 #endif /* VMS */
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));
30 #ifndef WIN_CE
31 #define Fprintf (void) fprintf
32 #else
33 #define Fprintf (void) nhce_message
34 static void nhce_message(FILE *, const char *, ...);
35 #endif
37 #define Close (void) close
39 #ifdef UNIX
40 #define SAVESIZE (PL_NSIZ + 13) /* save/99999player.e */
41 #else
42 #ifdef VMS
43 #define SAVESIZE (PL_NSIZ + 22) /* [.save]<uid>player.e;1 */
44 #else
45 #ifdef WIN32
46 #define SAVESIZE (PL_NSIZ + 40) /* username-player.aNetHack-saved-game */
47 #else
48 #define SAVESIZE FILENAME /* from macconf.h or pcconf.h */
49 #endif
50 #endif
51 #endif
53 #if defined(EXEPATH)
54 char *FDECL(exepath, (char *));
55 #endif
57 #if defined(__BORLANDC__) && !defined(_WIN32)
58 extern unsigned _stklen = STKSIZ;
59 #endif
60 char
61 savename[SAVESIZE]; /* holds relative path of save file from playground */
63 int
64 main(argc, argv)
65 int argc;
66 char *argv[];
68 int argno;
69 const char *dir = (char *) 0;
70 #ifdef AMIGA
71 char *startdir = (char *) 0;
72 #endif
74 if (!dir)
75 dir = getenv("ANETHACKDIR");
76 if (!dir)
77 dir = getenv("HACKDIR");
78 #if defined(EXEPATH)
79 if (!dir)
80 dir = exepath(argv[0]);
81 #endif
82 if (argc == 1 || (argc == 2 && !strcmp(argv[1], "-"))) {
83 Fprintf(stderr, "Usage: %s [ -d directory ] base1 [ base2 ... ]\n",
84 argv[0]);
85 #if defined(WIN32) || defined(MSDOS)
86 if (dir) {
87 Fprintf(
88 stderr,
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);
92 #endif
93 exit(EXIT_FAILURE);
96 argno = 1;
97 if (!strncmp(argv[argno], "-d", 2)) {
98 dir = argv[argno] + 2;
99 if (*dir == '=' || *dir == ':')
100 dir++;
101 if (!*dir && argc > argno) {
102 argno++;
103 dir = argv[argno];
105 if (!*dir) {
106 Fprintf(stderr,
107 "%s: flag -d must be followed by a directory name.\n",
108 argv[0]);
109 exit(EXIT_FAILURE);
111 argno++;
113 #if defined(SECURE) && !defined(VMS)
114 if (dir
115 #ifdef HACKDIR
116 && strcmp(dir, HACKDIR)
117 #endif
119 (void) setgid(getgid());
120 (void) setuid(getuid());
122 #endif /* SECURE && !VMS */
124 #ifdef HACKDIR
125 if (!dir)
126 dir = HACKDIR;
127 #endif
129 #ifdef AMIGA
130 startdir = getcwd(0, 255);
131 #endif
132 if (dir && chdir((char *) dir) < 0) {
133 Fprintf(stderr, "%s: cannot chdir to %s.\n", argv[0], dir);
134 exit(EXIT_FAILURE);
137 while (argc > argno) {
138 if (restore_savefile(argv[argno]) == 0)
139 Fprintf(stderr, "recovered \"%s\" to %s\n", argv[argno],
140 savename);
141 argno++;
143 #ifdef AMIGA
144 if (startdir)
145 (void) chdir(startdir);
146 #endif
147 exit(EXIT_SUCCESS);
148 /*NOTREACHED*/
149 return 0;
152 static char lock[256];
154 void
155 set_levelfile_name(lev)
156 int lev;
158 char *tf;
160 tf = rindex(lock, '.');
161 if (!tf)
162 tf = lock + strlen(lock);
163 (void) sprintf(tf, ".%d", lev);
164 #ifdef VMS
165 (void) strcat(tf, ";1");
166 #endif
170 open_levelfile(lev)
171 int lev;
173 int fd;
175 set_levelfile_name(lev);
176 #if defined(MICRO) || defined(WIN32) || defined(MSDOS)
177 fd = open(lock, O_RDONLY | O_BINARY);
178 #else
179 fd = open(lock, O_RDONLY, 0);
180 #endif
181 return fd;
185 create_savefile()
187 int fd;
189 #if defined(MICRO) || defined(WIN32) || defined(MSDOS)
190 fd = open(savename, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, FCMASK);
191 #else
192 fd = creat(savename, FCMASK);
193 #endif
194 return fd;
197 void
198 copy_bytes(ifd, ofd)
199 int ifd, ofd;
201 char buf[BUFSIZ];
202 int nfrom, nto;
204 do {
205 nfrom = read(ifd, buf, BUFSIZ);
206 nto = write(ofd, buf, nfrom);
207 if (nto != nfrom) {
208 Fprintf(stderr, "file copy failed!\n");
209 exit(EXIT_FAILURE);
211 } while (nfrom == BUFSIZ);
215 restore_savefile(basename)
216 char *basename;
218 int gfd, lfd, sfd;
219 int lev, savelev, hpid, pltmpsiz;
220 xchar levc;
221 struct version_info version_data;
222 struct savefile_info sfi;
223 char plbuf[PL_NSIZ];
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 anethack would have created
229 * savefile info
230 * player name
231 * and game state
233 (void) strcpy(lock, basename);
234 gfd = open_levelfile(0);
235 if (gfd < 0) {
236 #if defined(WIN32) && !defined(WIN_CE)
237 if (errno == EACCES) {
238 Fprintf(
239 stderr,
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");
243 } else
244 Fprintf(stderr, "\nTrouble accessing level 0 (errno = %d).\n",
245 errno);
246 #endif
247 Fprintf(stderr, "Cannot open level 0 for %s.\n", basename);
248 return (-1);
250 if (read(gfd, (genericptr_t) &hpid, sizeof hpid) != sizeof hpid) {
251 Fprintf(
252 stderr, "%s\n%s%s%s\n",
253 "Checkpoint data incompletely written or subsequently clobbered;",
254 "recovery for \"", basename, "\" impossible.");
255 Close(gfd);
256 return (-1);
258 if (read(gfd, (genericptr_t) &savelev, sizeof(savelev))
259 != sizeof(savelev)) {
260 Fprintf(stderr, "Checkpointing was not in effect for %s -- recovery "
261 "impossible.\n",
262 basename);
263 Close(gfd);
264 return (-1);
266 if ((read(gfd, (genericptr_t) savename, sizeof savename)
267 != 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);
275 Close(gfd);
276 return (-1);
279 /* save file should contain:
280 * version info
281 * savefile info
282 * player name
283 * current level (including pets)
284 * (non-level-based) game state
285 * other levels
287 sfd = create_savefile();
288 if (sfd < 0) {
289 Fprintf(stderr, "Cannot create savefile %s.\n", savename);
290 Close(gfd);
291 return (-1);
294 lfd = open_levelfile(savelev);
295 if (lfd < 0) {
296 Fprintf(stderr, "Cannot open level of save for %s.\n", basename);
297 Close(gfd);
298 Close(sfd);
299 return (-1);
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);
305 Close(gfd);
306 Close(sfd);
307 return (-1);
310 if (write(sfd, (genericptr_t) &sfi, sizeof sfi) != sizeof sfi) {
311 Fprintf(stderr,
312 "Error writing %s; recovery failed (savefile_info).\n",
313 savename);
314 Close(gfd);
315 Close(sfd);
316 return (-1);
319 if (write(sfd, (genericptr_t) &pltmpsiz, sizeof pltmpsiz)
320 != sizeof pltmpsiz) {
321 Fprintf(stderr,
322 "Error writing %s; recovery failed (player name size).\n",
323 savename);
324 Close(gfd);
325 Close(sfd);
326 return (-1);
329 if (write(sfd, (genericptr_t) &plbuf, pltmpsiz) != pltmpsiz) {
330 Fprintf(stderr, "Error writing %s; recovery failed (player name).\n",
331 savename);
332 Close(gfd);
333 Close(sfd);
334 return (-1);
337 copy_bytes(lfd, sfd);
338 Close(lfd);
339 (void) unlink(lock);
341 copy_bytes(gfd, sfd);
342 Close(gfd);
343 set_levelfile_name(0);
344 (void) unlink(lock);
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);
352 if (lfd >= 0) {
353 /* any or all of these may not exist */
354 levc = (xchar) lev;
355 write(sfd, (genericptr_t) &levc, sizeof(levc));
356 copy_bytes(lfd, sfd);
357 Close(lfd);
358 (void) unlink(lock);
363 Close(sfd);
365 #if 0 /* OBSOLETE, HackWB is no longer in use */
366 #ifdef AMIGA
367 /* we need to create an icon for the saved game
368 * or HackWB won't notice the file.
371 char iconfile[FILENAME];
372 int in, out;
374 (void) sprintf(iconfile, "%s.info", savename);
375 in = open("aNetHack:default.icon", O_RDONLY);
376 out = open(iconfile, O_WRONLY | O_TRUNC | O_CREAT);
377 if(in > -1 && out > -1){
378 copy_bytes(in,out);
380 if(in > -1)close(in);
381 if(out > -1)close(out);
383 #endif
384 #endif
385 return (0);
388 #ifdef EXEPATH
389 #ifdef __DJGPP__
390 #define PATH_SEPARATOR '/'
391 #else
392 #define PATH_SEPARATOR '\\'
393 #endif
395 #define EXEPATHBUFSZ 256
396 char exepathbuf[EXEPATHBUFSZ];
398 char *
399 exepath(str)
400 char *str;
402 char *tmp, *tmp2;
403 int bsize;
405 if (!str)
406 return (char *) 0;
407 bsize = EXEPATHBUFSZ;
408 tmp = exepathbuf;
409 #if !defined(WIN32)
410 strcpy(tmp, str);
411 #else
412 #if defined(WIN_CE)
414 TCHAR wbuf[EXEPATHBUFSZ];
415 GetModuleFileName((HANDLE) 0, wbuf, EXEPATHBUFSZ);
416 NH_W2A(wbuf, tmp, bsize);
418 #else
419 *(tmp + GetModuleFileName((HANDLE) 0, tmp, bsize)) = '\0';
420 #endif
421 #endif
422 tmp2 = strrchr(tmp, PATH_SEPARATOR);
423 if (tmp2)
424 *tmp2 = '\0';
425 return tmp;
427 #endif /* EXEPATH */
429 #ifdef AMIGA
430 #include "date.h"
431 const char amiga_version_string[] = AMIGA_VERSION_STRING;
432 #endif
434 #ifdef WIN_CE
435 void
436 nhce_message(FILE *f, const char *str, ...)
438 va_list ap;
439 TCHAR wbuf[NHSTR_BUFSIZE];
440 char buf[NHSTR_BUFSIZE];
442 va_start(ap, str);
443 vsprintf(buf, str, ap);
444 va_end(ap);
446 MessageBox(NULL, NH_A2W(buf, wbuf, NHSTR_BUFSIZE), TEXT("Recover"),
447 MB_OK);
449 #endif
451 /*recover.c*/