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 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;
60
char savename[SAVESIZE]; /* holds relative path of save file from playground */
69
const char *dir = (char *)0;
71
char *startdir = (char *)0;
75
if (!dir) dir = getenv("NETHACKDIR");
76
if (!dir) dir = getenv("HACKDIR");
78
if (!dir) dir = exepath(argv[0]);
80
if (argc == 1 || (argc == 2 && !strcmp(argv[1], "-"))) {
82
"Usage: %s [ -d directory ] base1 [ base2 ... ]\n", argv[0]);
83
#if defined(WIN32) || defined(MSDOS)
85
Fprintf(stderr, "\t(Unless you override it with -d, recover will look \n");
86
Fprintf(stderr, "\t in the %s directory on your system)\n", dir);
93
if (!strncmp(argv[argno], "-d", 2)) {
95
if (*dir == '=' || *dir == ':') dir++;
96
if (!*dir && argc > argno) {
102
"%s: flag -d must be followed by a directory name.\n",
108
#if defined(SECURE) && !defined(VMS)
111
&& strcmp(dir, HACKDIR)
114
(void) setgid(getgid());
115
(void) setuid(getuid());
117
#endif /* SECURE && !VMS */
120
if (!dir) dir = HACKDIR;
124
startdir = getcwd(0,255);
126
if (dir && chdir((char *) dir) < 0) {
127
Fprintf(stderr, "%s: cannot chdir to %s.\n", argv[0], dir);
131
while (argc > argno) {
132
if (restore_savefile(argv[argno]) == 0)
133
Fprintf(stderr, "recovered \"%s\" to %s\n",
134
argv[argno], savename);
138
if (startdir) (void)chdir(startdir);
145
static char lock[256];
148
set_levelfile_name(lev)
153
tf = rindex(lock, '.');
154
if (!tf) tf = lock + strlen(lock);
155
(void) sprintf(tf, ".%d", lev);
157
(void) strcat(tf, ";1");
167
set_levelfile_name(lev);
168
#if defined(MICRO) || defined(WIN32) || defined(MSDOS)
169
fd = open(lock, O_RDONLY | O_BINARY);
171
fd = open(lock, O_RDONLY, 0);
181
#if defined(MICRO) || defined(WIN32) || defined(MSDOS)
182
fd = open(savename, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, FCMASK);
184
fd = creat(savename, FCMASK);
197
nfrom = read(ifd, buf, BUFSIZ);
198
nto = write(ofd, buf, nfrom);
200
Fprintf(stderr, "file copy failed!\n");
203
} while (nfrom == BUFSIZ);
207
restore_savefile(basename)
211
int lev, savelev, hpid;
213
struct version_info version_data;
215
/* level 0 file contains:
216
* pid of creating process (ignored here)
217
* level number for current level of save file
218
* name of save file nethack would have created
221
(void) strcpy(lock, basename);
222
gfd = open_levelfile(0);
224
#if defined(WIN32) && !defined(WIN_CE)
225
if(errno == EACCES) {
227
"\nThere are files from a game in progress under your name.");
228
Fprintf(stderr,"\nThe files are locked or inaccessible.");
229
Fprintf(stderr,"\nPerhaps the other game is still running?\n");
232
"\nTrouble accessing level 0 (errno = %d).\n", errno);
234
Fprintf(stderr, "Cannot open level 0 for %s.\n", basename);
237
if (read(gfd, (genericptr_t) &hpid, sizeof hpid) != sizeof hpid) {
238
Fprintf(stderr, "%s\n%s%s%s\n",
239
"Checkpoint data incompletely written or subsequently clobbered;",
240
"recovery for \"", basename, "\" impossible.");
244
if (read(gfd, (genericptr_t) &savelev, sizeof(savelev))
245
!= sizeof(savelev)) {
247
"Checkpointing was not in effect for %s -- recovery impossible.\n",
252
if ((read(gfd, (genericptr_t) savename, sizeof savename)
253
!= sizeof savename) ||
254
(read(gfd, (genericptr_t) &version_data, sizeof version_data)
255
!= sizeof version_data)) {
256
Fprintf(stderr, "Error reading %s -- can't recover.\n", lock);
261
/* save file should contain:
263
* current level (including pets)
264
* (non-level-based) game state
267
sfd = create_savefile();
269
Fprintf(stderr, "Cannot create savefile %s.\n", savename);
274
lfd = open_levelfile(savelev);
276
Fprintf(stderr, "Cannot open level of save for %s.\n", basename);
282
if (write(sfd, (genericptr_t) &version_data, sizeof version_data)
283
!= sizeof version_data) {
284
Fprintf(stderr, "Error writing %s; recovery failed.\n", savename);
290
copy_bytes(lfd, sfd);
294
copy_bytes(gfd, sfd);
296
set_levelfile_name(0);
299
for (lev = 1; lev < 256; lev++) {
300
/* level numbers are kept in xchars in save.c, so the
301
* maximum level number (for the endlevel) must be < 256
303
if (lev != savelev) {
304
lfd = open_levelfile(lev);
306
/* any or all of these may not exist */
308
write(sfd, (genericptr_t) &levc, sizeof(levc));
309
copy_bytes(lfd, sfd);
318
#if 0 /* OBSOLETE, HackWB is no longer in use */
320
/* we need to create an icon for the saved game
321
* or HackWB won't notice the file.
324
char iconfile[FILENAME];
327
(void) sprintf(iconfile, "%s.info", savename);
328
in = open("NetHack:default.icon", O_RDONLY);
329
out = open(iconfile, O_WRONLY | O_TRUNC | O_CREAT);
330
if(in > -1 && out > -1){
333
if(in > -1)close(in);
334
if(out > -1)close(out);
343
#define PATH_SEPARATOR '/'
345
#define PATH_SEPARATOR '\\'
348
#define EXEPATHBUFSZ 256
349
char exepathbuf[EXEPATHBUFSZ];
357
if (!str) return (char *)0;
358
bsize = EXEPATHBUFSZ;
365
TCHAR wbuf[EXEPATHBUFSZ];
366
GetModuleFileName((HANDLE)0, wbuf, EXEPATHBUFSZ);
367
NH_W2A(wbuf, tmp, bsize);
370
*(tmp + GetModuleFileName((HANDLE)0, tmp, bsize)) = '\0';
373
tmp2 = strrchr(tmp, PATH_SEPARATOR);
374
if (tmp2) *tmp2 = '\0';
381
const char amiga_version_string[] = AMIGA_VERSION_STRING;
385
void nhce_message(FILE* f, const char* str, ...)
388
TCHAR wbuf[NHSTR_BUFSIZE];
389
char buf[NHSTR_BUFSIZE];
392
vsprintf(buf, str, ap);
395
MessageBox(NULL, NH_A2W(buf, wbuf, NHSTR_BUFSIZE), TEXT("Recover"), MB_OK);