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. */
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 vms_creat(const char *,unsigned);
21 extern int vms_open(const char *,int,unsigned);
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);
32 #define SAVESIZE (PL_NSIZ + 13) /* save/99999player.e */
35 #define SAVESIZE (PL_NSIZ + 22) /* [.save]<uid>player.e;1 */
38 #define SAVESIZE (PL_NSIZ + 40) /* username-player.NetHack-saved-game */
40 #define SAVESIZE FILENAMELEN /* from macconf.h or pcconf.h */
46 char *exepath(char *);
49 #if defined(__BORLANDC__) && !defined(_WIN32)
50 extern unsigned _stklen
= STKSIZ
;
52 char savename
[SAVESIZE
]; /* holds relative path of save file from playground */
56 recover_main(argc
, argv
)
61 const char *dir
= (char *)0;
63 char *startdir
= (char *)0;
67 if (!dir
) dir
= getenv("NETHACKDIR");
68 if (!dir
) dir
= getenv("HACKDIR");
70 if (!dir
) dir
= FILE_AREA_LEVL
;
74 if (!dir
) dir
= exepath(argv
[0]);
76 if (argc
== 1 || (argc
== 2 && !strcmp(argv
[1], "-"))) {
78 "Usage: %s [ -d directory ] base1 [ base2 ... ]\n", argv
[0]);
79 #if defined(WIN32) || defined(MSDOS)
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
);
89 if (!strncmp(argv
[argno
], "-d", 2)) {
91 if (*dir
== '=' || *dir
== ':') dir
++;
92 if (!*dir
&& argc
> argno
) {
98 "%s: flag -d must be followed by a directory name.\n",
104 #if defined(SECURE) && !defined(VMS)
107 && strcmp(dir
, HACKDIR
)
110 (void) setgid(getgid());
111 (void) setuid(getuid());
113 #endif /* SECURE && !VMS */
116 if (!dir
) dir
= HACKDIR
;
120 startdir
= getcwd(0,255);
122 if (dir
&& chdir((char *) dir
) < 0) {
123 fprintf(stderr
, "%s: cannot chdir to %s.\n", argv
[0], dir
);
127 while (argc
> argno
) {
128 if (restore_savefile(argv
[argno
], dir
) == 0)
129 fprintf(stderr
, "recovered \"%s\" to %s\n",
130 argv
[argno
], savename
);
134 if (startdir
) (void)chdir(startdir
);
141 static char lock
[256];
144 set_levelfile_name(lev
)
149 tf
= rindex(lock
, '.');
150 if (!tf
) tf
= lock
+ strlen(lock
);
151 (void) sprintf(tf
, ".%d", lev
);
153 (void) strcat(tf
, ";1");
158 open_levelfile(lev
, directory
)
160 const char *directory
;
163 char levelfile
[BUFSIZ
];
165 set_levelfile_name(lev
);
167 snprintf(levelfile
, BUFSIZ
, "%s/%s", directory
, lock
);
169 strcpy(levelfile
, lock
);
171 #if defined(MICRO) || defined(WIN32) || defined(MSDOS)
172 fd
= open(levelfile
, O_RDONLY
| O_BINARY
);
174 fd
= open(levelfile
, O_RDONLY
, 0);
180 create_savefile(directory
)
181 const char *directory
;
184 char savefile
[BUFSIZ
];
187 sprintf(savefile
, "%s/%s", directory
, savename
);
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
);
194 fd
= creat(savefile
, FCMASK
);
207 nfrom
= read(ifd
, buf
, BUFSIZ
);
208 nto
= write(ofd
, buf
, nfrom
);
210 fprintf(stderr
,"%s", "file copy failed!\n");
213 } while (nfrom
== BUFSIZ
);
217 restore_savefile(basename
, directory
)
219 const char *directory
;
222 int lev
, savelev
, hpid
;
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
232 (void) strcpy(lock
, basename
);
233 gfd
= open_levelfile(0, directory
);
235 #if defined(WIN32) && !defined(WIN_CE)
236 if(errno
== EACCES
) {
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");
243 "\nTrouble accessing level 0 (errno = %d).\n", errno
);
245 fprintf(stderr
, "Cannot open level 0 for %s.\n", basename
);
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.");
255 if (read(gfd
, (void *) &savelev
, sizeof(savelev
))
256 != sizeof(savelev
)) {
258 "Checkpointing was not in effect for %s -- recovery impossible.\n",
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
);
272 /* save file should contain:
274 * current level (including pets)
275 * (non-level-based) game state
279 sfd
= create_savefile(FILE_AREA_SAVE
);
281 sfd
= create_savefile(directory
);
284 fprintf(stderr
, "Cannot create savefile %s.\n", savename
);
289 lfd
= open_levelfile(savelev
, directory
);
291 fprintf(stderr
, "Cannot open level of save for %s.\n", basename
);
297 if (write(sfd
, (void *) &version_data
, sizeof version_data
)
298 != sizeof version_data
) {
299 fprintf(stderr
, "Error writing %s; recovery failed.\n", savename
);
305 copy_bytes(lfd
, sfd
);
309 copy_bytes(gfd
, sfd
);
311 set_levelfile_name(0);
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
);
323 /* any or all of these may not exist */
325 write(sfd
, (void *) &levc
, sizeof(levc
));
326 copy_bytes(lfd
, sfd
);
335 #if 0 /* OBSOLETE, HackWB is no longer in use */
337 /* we need to create an icon for the saved game
338 * or HackWB won't notice the file.
341 char iconfile
[FILENAME
];
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){
350 if(in
> -1)close(in
);
351 if(out
> -1)close(out
);
360 #define PATH_SEPARATOR '/'
362 #define PATH_SEPARATOR '\\'
365 #define EXEPATHBUFSZ 256
366 char exepathbuf
[EXEPATHBUFSZ
];
374 if (!str
) return (char *)0;
375 bsize
= EXEPATHBUFSZ
;
382 TCHAR wbuf
[EXEPATHBUFSZ
];
383 GetModuleFileName((HANDLE
)0, wbuf
, EXEPATHBUFSZ
);
384 NH_W2A(wbuf
, tmp
, bsize
);
387 *(tmp
+ GetModuleFileName((HANDLE
)0, tmp
, bsize
)) = '\0';
390 tmp2
= strrchr(tmp
, PATH_SEPARATOR
);
391 if (tmp2
) *tmp2
= '\0';
398 const char amiga_version_string
[] = AMIGA_VERSION_STRING
;
402 void nhce_message(FILE* f
, const char* str
, ...)
405 TCHAR wbuf
[NHSTR_BUFSIZE
];
406 char buf
[NHSTR_BUFSIZE
];
409 vsprintf(buf
, str
, ap
);
412 MessageBox(NULL
, NH_A2W(buf
, wbuf
, NHSTR_BUFSIZE
), TEXT("Recover"), MB_OK
);