Blindfold removal fix
[slashemextended.git] / src / recover.c
blob5ddfacd20d82c643e7e6a7c3e5aac038845fd2fd
1 /* SCCS Id: @(#)recover.c 3.4 1999/10/23 */
2 /* Copyright (c) Janet Walz, 1992. */
3 /* NetHack may be freely redistributed. See license for details. */
5 /*
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.
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 vms_creat(const char *,unsigned);
21 extern int vms_open(const char *,int,unsigned);
22 #endif /* VMS */
24 int recover_main(int, char *[]);
25 int restore_savefile(char *, const char *);
26 static void set_levelfile_name(int);
27 static int open_levelfile(int, const char *);
28 static int create_savefile(const char *);
29 void copy_bytes(int,int);
31 #ifdef UNIX
32 #define SAVESIZE (PL_NSIZ + 13) /* save/99999player.e */
33 #else
34 # ifdef VMS
35 #define SAVESIZE (PL_NSIZ + 22) /* [.save]<uid>player.e;1 */
36 # else
37 # ifdef WIN32
38 #define SAVESIZE (PL_NSIZ + 40) /* username-player.NetHack-saved-game */
39 # else
40 #define SAVESIZE FILENAMELEN /* from macconf.h or pcconf.h */
41 # endif
42 # endif
43 #endif
45 #if defined(EXEPATH)
46 char *exepath(char *);
47 #endif
49 #if defined(__BORLANDC__) && !defined(_WIN32)
50 extern unsigned _stklen = STKSIZ;
51 #endif
52 char savename[SAVESIZE]; /* holds relative path of save file from playground */
55 int
56 recover_main(argc, argv)
57 int argc;
58 char *argv[];
60 int argno;
61 const char *dir = (char *)0;
62 #ifdef AMIGA
63 char *startdir = (char *)0;
64 #endif
67 if (!dir) dir = getenv("NETHACKDIR");
68 if (!dir) dir = getenv("HACKDIR");
69 #ifdef FILE_AREAS
70 if (!dir) dir = FILE_AREA_LEVL;
71 #endif
73 #if defined(EXEPATH)
74 if (!dir) dir = exepath(argv[0]);
75 #endif
76 if (argc == 1 || (argc == 2 && !strcmp(argv[1], "-"))) {
77 fprintf(stderr,
78 "Usage: %s [ -d directory ] base1 [ base2 ... ]\n", argv[0]);
79 #if defined(WIN32) || defined(MSDOS)
80 if (dir) {
81 fprintf(stderr, "\t(Unless you override it with -d, recover will look \n");
82 fprintf(stderr, "\t in the %s directory on your system)\n", dir);
84 #endif
85 exit(EXIT_FAILURE);
88 argno = 1;
89 if (!strncmp(argv[argno], "-d", 2)) {
90 dir = argv[argno]+2;
91 if (*dir == '=' || *dir == ':') dir++;
92 if (!*dir && argc > argno) {
93 argno++;
94 dir = argv[argno];
96 if (!*dir) {
97 fprintf(stderr,
98 "%s: flag -d must be followed by a directory name.\n",
99 argv[0]);
100 exit(EXIT_FAILURE);
102 argno++;
104 #if defined(SECURE) && !defined(VMS)
105 if (dir
106 # ifdef HACKDIR
107 && strcmp(dir, HACKDIR)
108 # endif
110 (void) setgid(getgid());
111 (void) setuid(getuid());
113 #endif /* SECURE && !VMS */
115 #ifdef HACKDIR
116 if (!dir) dir = HACKDIR;
117 #endif
119 #ifdef AMIGA
120 startdir = getcwd(0,255);
121 #endif
122 if (dir && chdir((char *) dir) < 0) {
123 fprintf(stderr, "%s: cannot chdir to %s.\n", argv[0], dir);
124 exit(EXIT_FAILURE);
127 while (argc > argno) {
128 if (restore_savefile(argv[argno], dir) == 0)
129 fprintf(stderr, "recovered \"%s\" to %s\n",
130 argv[argno], savename);
131 argno++;
133 #ifdef AMIGA
134 if (startdir) (void)chdir(startdir);
135 #endif
136 exit(EXIT_SUCCESS);
137 /*NOTREACHED*/
138 return 0;
141 static char lock[256];
143 static void
144 set_levelfile_name(lev)
145 int lev;
147 char *tf;
149 tf = rindex(lock, '.');
150 if (!tf) tf = lock + strlen(lock);
151 (void) sprintf(tf, ".%d", lev);
152 #ifdef VMS
153 (void) strcat(tf, ";1");
154 #endif
157 static int
158 open_levelfile(lev, directory)
159 int lev;
160 const char *directory;
162 int fd;
163 char levelfile[BUFSIZ];
165 set_levelfile_name(lev);
166 if (directory) {
167 snprintf(levelfile, BUFSIZ, "%s/%s", directory, lock);
168 } else {
169 strcpy(levelfile, lock);
171 #if defined(MICRO) || defined(WIN32) || defined(MSDOS)
172 fd = open(levelfile, O_RDONLY | O_BINARY);
173 #else
174 fd = open(levelfile, O_RDONLY, 0);
175 #endif
176 return fd;
179 static int
180 create_savefile(directory)
181 const char *directory;
183 int fd;
184 char savefile[BUFSIZ];
186 if (directory) {
187 sprintf(savefile, "%s/%s", directory, savename);
188 } else {
189 strcpy(savefile, savename);
191 #if defined(MICRO) || defined(WIN32) || defined(MSDOS)
192 fd = open(savefile, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, FCMASK);
193 #else
194 fd = creat(savefile, FCMASK);
195 #endif
196 return fd;
199 void
200 copy_bytes(ifd, ofd)
201 int ifd, ofd;
203 char buf[BUFSIZ];
204 int nfrom, nto;
206 do {
207 nfrom = read(ifd, buf, BUFSIZ);
208 nto = write(ofd, buf, nfrom);
209 if (nto != nfrom) {
210 fprintf(stderr,"%s", "file copy failed!\n");
211 exit(EXIT_FAILURE);
213 } while (nfrom == BUFSIZ);
217 restore_savefile(basename, directory)
218 char *basename;
219 const char *directory;
221 int gfd, lfd, sfd;
222 int lev, savelev, hpid;
223 xchar levc;
224 struct version_info version_data;
226 /* level 0 file contains:
227 * pid of creating process (ignored here)
228 * level number for current level of save file
229 * name of save file nethack would have created
230 * and game state
232 (void) strcpy(lock, basename);
233 gfd = open_levelfile(0, directory);
234 if (gfd < 0) {
235 #if defined(WIN32) && !defined(WIN_CE)
236 if(errno == EACCES) {
237 fprintf(stderr,
238 "\nThere are files from a game in progress under your name.");
239 fprintf(stderr,"%s","\nThe files are locked or inaccessible.");
240 fprintf(stderr,"%s","\nPerhaps the other game is still running?\n");
241 } else
242 fprintf(stderr,
243 "\nTrouble accessing level 0 (errno = %d).\n", errno);
244 #endif
245 fprintf(stderr, "Cannot open level 0 for %s.\n", basename);
246 return(-1);
248 if (read(gfd, (void *) &hpid, sizeof hpid) != sizeof hpid) {
249 fprintf(stderr, "%s\n%s%s%s\n",
250 "Checkpoint data incompletely written or subsequently clobbered;",
251 "recovery for \"", basename, "\" impossible.");
252 close(gfd);
253 return(-1);
255 if (read(gfd, (void *) &savelev, sizeof(savelev))
256 != sizeof(savelev)) {
257 fprintf(stderr,
258 "Checkpointing was not in effect for %s -- recovery impossible.\n",
259 basename);
260 close(gfd);
261 return(-1);
263 if ((read(gfd, (void *) savename, sizeof savename)
264 != sizeof savename) ||
265 (read(gfd, (void *) &version_data, sizeof version_data)
266 != sizeof version_data)) {
267 fprintf(stderr, "Error reading %s -- can't recover.\n", lock);
268 close(gfd);
269 return(-1);
272 /* save file should contain:
273 * version info
274 * current level (including pets)
275 * (non-level-based) game state
276 * other levels
278 #ifdef FILE_AREAS
279 sfd = create_savefile(FILE_AREA_SAVE);
280 #else
281 sfd = create_savefile(directory);
282 #endif
283 if (sfd < 0) {
284 fprintf(stderr, "Cannot create savefile %s.\n", savename);
285 close(gfd);
286 return(-1);
289 lfd = open_levelfile(savelev, directory);
290 if (lfd < 0) {
291 fprintf(stderr, "Cannot open level of save for %s.\n", basename);
292 close(gfd);
293 close(sfd);
294 return(-1);
297 if (write(sfd, (void *) &version_data, sizeof version_data)
298 != sizeof version_data) {
299 fprintf(stderr, "Error writing %s; recovery failed.\n", savename);
300 close(gfd);
301 close(sfd);
302 return(-1);
305 copy_bytes(lfd, sfd);
306 close(lfd);
307 (void) unlink(lock);
309 copy_bytes(gfd, sfd);
310 close(gfd);
311 set_levelfile_name(0);
312 (void) unlink(lock);
314 for (lev = 1; lev < 5000; lev++) {
315 /* level numbers are kept in xchars in save.c, so the
316 * maximum level number (for the endlevel) must be < 256
317 * Amy edit: no longer the case!
318 * this number must always be higher than the maximum possible amount of levels
320 if (lev != savelev) {
321 lfd = open_levelfile(lev, directory);
322 if (lfd >= 0) {
323 /* any or all of these may not exist */
324 levc = (xchar) lev;
325 write(sfd, (void *) &levc, sizeof(levc));
326 copy_bytes(lfd, sfd);
327 close(lfd);
328 (void) unlink(lock);
333 close(sfd);
335 #if 0 /* OBSOLETE, HackWB is no longer in use */
336 #ifdef AMIGA
337 /* we need to create an icon for the saved game
338 * or HackWB won't notice the file.
341 char iconfile[FILENAME];
342 int in, out;
344 (void) sprintf(iconfile, "%s.info", savename);
345 in = open("NetHack:default.icon", O_RDONLY);
346 out = open(iconfile, O_WRONLY | O_TRUNC | O_CREAT);
347 if(in > -1 && out > -1){
348 copy_bytes(in,out);
350 if(in > -1)close(in);
351 if(out > -1)close(out);
353 #endif
354 #endif
355 return(0);
358 #ifdef EXEPATH
359 # ifdef __DJGPP__
360 #define PATH_SEPARATOR '/'
361 # else
362 #define PATH_SEPARATOR '\\'
363 # endif
365 #define EXEPATHBUFSZ 256
366 char exepathbuf[EXEPATHBUFSZ];
368 char *exepath(str)
369 char *str;
371 char *tmp, *tmp2;
372 int bsize;
374 if (!str) return (char *)0;
375 bsize = EXEPATHBUFSZ;
376 tmp = exepathbuf;
377 #if !defined(WIN32)
378 strcpy (tmp, str);
379 #else
380 # if defined(WIN_CE)
382 TCHAR wbuf[EXEPATHBUFSZ];
383 GetModuleFileName((HANDLE)0, wbuf, EXEPATHBUFSZ);
384 NH_W2A(wbuf, tmp, bsize);
386 # else
387 *(tmp + GetModuleFileName((HANDLE)0, tmp, bsize)) = '\0';
388 # endif
389 #endif
390 tmp2 = strrchr(tmp, PATH_SEPARATOR);
391 if (tmp2) *tmp2 = '\0';
392 return tmp;
394 #endif /* EXEPATH */
396 #ifdef AMIGA
397 #include "date.h"
398 const char amiga_version_string[] = AMIGA_VERSION_STRING;
399 #endif
401 #ifdef WIN_CE
402 void nhce_message(FILE* f, const char* str, ...)
404 va_list ap;
405 TCHAR wbuf[NHSTR_BUFSIZE];
406 char buf[NHSTR_BUFSIZE];
408 va_start(ap, str);
409 vsprintf(buf, str, ap);
410 va_end(ap);
412 MessageBox(NULL, NH_A2W(buf, wbuf, NHSTR_BUFSIZE), TEXT("Recover"), MB_OK);
414 #endif
416 /*recover.c*/