/** * Save a set of preferences to file, overwriting any old preferences with the * same title. * * \param path is the filename to dump to * \param dump is a pointer to the function that does the writing to file * \param title is the name of this set of preferences * * \returns TRUE on success, FALSE otherwise. */ bool prefs_save(const char *path, void (*dump) (ang_file *), const char *title) { ang_file *fff; safe_setuid_grab(); /* Remove old keymaps */ remove_old_dump(path, title); fff = file_open(path, MODE_APPEND, FTYPE_TEXT); if (!fff) { safe_setuid_drop(); return FALSE; } /* Append the header */ pref_header(fff, title); file_putf(fff, "\n\n"); file_putf(fff, "# %s definitions\n\n", strstr(title, " ")); dump(fff); file_putf(fff, "\n\n\n"); pref_footer(fff, title); file_close(fff); safe_setuid_drop(); return TRUE; }
/* * Actually read the savefile */ errr rd_savefile(void) { errr err; /* Grab permissions */ safe_setuid_grab(); /* The savefile is a binary file */ fff = my_fopen(savefile, "rb"); /* Drop permissions */ safe_setuid_drop(); /* Paranoia */ if (!fff) return (-1); /* Call the sub-function */ err = rd_savefile_new_aux(); /* Check for errors */ if (ferror(fff)) err = -1; /* Close the file */ my_fclose(fff); /* Result */ return (err); }
/*! * @brief 参照ポインタ先の保存フロアを抹消する / kill a saved floor and get an empty space * @param sf_ptr 保存フロアの参照ポインタ * @return なし */ static void kill_saved_floor(saved_floor_type *sf_ptr) { char floor_savefile[1024]; /* Paranoia */ if (!sf_ptr) return; /* Already empty */ if (!sf_ptr->floor_id) return; if (sf_ptr->floor_id == p_ptr->floor_id) { /* Kill current floor */ p_ptr->floor_id = 0; /* Current floor doesn't have temporal file */ } else { /* File name */ sprintf(floor_savefile, "%s.F%02d", savefile, (int)sf_ptr->savefile_id); /* Grab permissions */ safe_setuid_grab(); /* Simply kill the temporal file */ (void)fd_kill(floor_savefile); /* Drop permissions */ safe_setuid_drop(); } /* No longer exists */ sf_ptr->floor_id = 0; }
/* * Initialise things for multiuser machines * Pay special attention to permisions. */ void init_setuid(void) { /* Default permissions on files */ (void)umask(022); /* Get the user id (?) */ player_uid = getuid(); #ifdef VMS /* Mega-Hack -- Factor group id */ player_uid += (getgid() * 1000); #endif /* VMS */ #ifdef SAFE_SETUID #if defined(HAVE_SETEGID) || defined(SAFE_SETUID_POSIX) /* Save some info for later */ player_euid = geteuid(); player_egid = getegid(); #endif /* defined(HAVE_SETEGID) || defined(SAFE_SETUID_POSIX) */ /* XXX XXX XXX */ #if 0 /* Redundant setting necessary in case root is running the game */ /* If not root or game not setuid the following two calls do nothing */ if (setgid(getegid()) != 0) { quit("setgid(): cannot set permissions correctly!"); } if (setuid(geteuid()) != 0) { quit("setuid(): cannot set permissions correctly!"); } #endif /* 0 */ #endif /* SAFE_SETUID */ /* Drop permissions */ safe_setuid_drop(); /* Get the "user name" as a default player name */ user_name(player_name, player_uid); }
/* * Open a given text file in the user directory for writing. */ static FILE *my_fopen_wiz(cptr fname) { /* File type is "TEXT" */ FILE_TYPE(FILE_TYPE_TEXT); /* Drop priv's */ safe_setuid_drop(); /* Build and open the filename with the standard name. */ fff = my_fopen_path(ANGBAND_DIR_USER, fname, "w"); /* Grab priv's */ safe_setuid_grab(); /* Warn of errors. */ if (!fff) msg_print("Cannot create spoiler file."); return fff; }
/* * Actually read the savefile */ int rd_savefile_old(void) { errr err; /* Open savefile */ safe_setuid_grab(); fff = file_open(savefile, MODE_READ, -1); safe_setuid_drop(); /* Paranoia */ if (!fff) return (-1); /* Call the sub-function */ err = rd_savefile_new_aux(); /* Close the file */ file_close(fff); /* Result */ return (err); }
/*! * @brief 保存フロア用テンポラリファイルを削除する / Kill temporal files * @details Should be called just before the game quit. * @return なし */ void clear_saved_floor_files(void) { char floor_savefile[1024]; int i; #ifdef SET_UID # ifdef SECURE /* Get "games" permissions */ beGames(); # endif #endif for (i = 0; i < MAX_SAVED_FLOORS; i++) { saved_floor_type *sf_ptr = &saved_floors[i]; /* No temporal file */ if (!sf_ptr->floor_id) continue; if (sf_ptr->floor_id == p_ptr->floor_id) continue; /* File name */ sprintf(floor_savefile, "%s.F%02d", savefile, i); /* Grab permissions */ safe_setuid_grab(); /* Simply kill the temporal file */ (void)fd_kill(floor_savefile); /* Drop permissions */ safe_setuid_drop(); } #ifdef SET_UID # ifdef SECURE /* Drop "games" permissions */ bePlayer(); # endif #endif }
/* * Create an ".angband/" directory in the users home directory. * * ToDo: Add error handling. * ToDo: Only create the directories when actually writing files. */ static void create_user_dir(void) { char dirpath[1024]; char subdirpath[1024]; /* Drop privs */ safe_setuid_drop(); /* Get an absolute path from the filename */ path_parse(dirpath, 1024, PRIVATE_USER_PATH); /* Create the ~/.angband/ directory */ mkdir(dirpath, 0700); /* Build the path to the variant-specific sub-directory */ path_build(subdirpath, 1024, dirpath, VERSION_NAME); /* Create the directory */ mkdir(subdirpath, 0700); /* Grab privs */ safe_setuid_grab(); }
/* * Save a "bones" file for a dead character * * Should probably attempt some form of locking... */ void make_bones(void) { #if 0 /* DGDGDGDG */ FILE *fp; int i; char str[1024]; /* Ignore wizards and borgs */ if (!(noscore & 0x00FF)) { /* Ignore people who die in town */ if (dun_level) { int level; char tmp[128]; /* Slightly more tenacious saving routine. */ for (i = 0; i < 5; i++) { /* Ghost hovers near level of death. */ if (i == 0) level = dun_level; else level = dun_level + 5 - damroll(2, 4); if (level < 1) level = randint(4); /* XXX XXX XXX "Bones" name */ sprintf(tmp, "bone%03d.%03d", dungeon_type, level); /* Build the filename */ path_build(str, 1024, ANGBAND_DIR_BONE, tmp); /* Grab permission */ safe_setuid_grab(); /* Attempt to open the bones file */ fp = my_fopen(str, "r"); /* Drop permission */ safe_setuid_drop(); /* Close it right away */ if (fp) my_fclose(fp); /* Do not over-write a previous ghost */ if (fp) continue; /* If no file by that name exists, we can make a new one. */ if (!(fp)) break; } /* File type is "TEXT" */ FILE_TYPE(FILE_TYPE_TEXT); /* Grab permission */ safe_setuid_grab(); /* Try to write a new "Bones File" */ fp = my_fopen(str, "w"); /* Drop permission */ safe_setuid_drop(); /* Not allowed to write it? Weird. */ if (!fp) return; /* Save the info */ fprintf(fp, "%s\n", player_name); fprintf(fp, "%d\n", p_ptr->mhp); fprintf(fp, "%d\n", p_ptr->prace); fprintf(fp, "%d\n", p_ptr->pclass); /* Close and save the Bones file */ my_fclose(fp); } } #endif }
// TODO: Hookify this void close_game(void) { char buf[1024]; /* Handle stuff */ handle_stuff(); /* Flush the messages */ message_flush(); /* Flush the input */ flush(); /* No suspending now */ signals_ignore_tstp(); #ifndef AVT_HOOKIFY_EXIT /* Hack -- Increase "icky" depth */ character_icky++; /* Build the filename */ path_build(buf, sizeof(buf), ANGBAND_DIR_APEX, "scores.raw"); /* Grab permissions */ safe_setuid_grab(); /* Open the high score file, for reading/writing */ highscore_fd = fd_open(buf, O_RDWR); /* Drop permissions */ safe_setuid_drop(); /* Handle death */ if (p_ptr->is_dead) { /* Auxiliary routine */ close_game_aux(); } /* Still alive */ else { /* Save the game */ do_cmd_save_game(); /* Prompt for scores XXX XXX XXX */ prt("Press Return (or Escape).", 0, 40); /* Predict score (or ESCAPE) */ if (inkey() != ESCAPE) predict_score(); } /* Shut the high score file */ fd_close(highscore_fd); /* Forget the high score fd */ highscore_fd = -1; /* Hack -- Decrease "icky" depth */ character_icky--; #endif /* Allow suspending now */ signals_handle_tstp(); }
/* * This function outputs a MATLAB 'm'file that can * be used to balance the monster distribution in the * game. * * Run this function, then do the following: * 1) copy monmatlb.m from the /lib/save directory to * a directory in the matlab path. * 2) type "monmatlb" in MATLAB. * 3) The matrix is called xx, the monster depths are y, * the monster xp values are xp. * 4) Now the balanced values are calculated: * 5) Type: "a1=xx\y';" * 6) Type: "r1=xx*a1;" * 7) Type: "level=r1*100/550;" * 8) Type: "i=20:884;" (Note these are the values of min * and max used below in the code. * 9) Type: "[i' round(level)]" MATLAB should now print out a table * of monster number vs new monster depth. * 10) To work out the new xp values: * 11) Type: "xp2=xp.^(0.15);" This function scales the xp so * that it seems to be linear with the new monster distribution. * 12) Type: "a2=xx\xp2';" * 13) Type: "r2=xx*a2;" * 14) Type: "xp3=round(r2.^(1/0.15))" MATLAB should now print a list * of the new xp values... use your favourite editor to move this * list next to the old one. NOTE: My version of matlab cannot * print out the monster number next to the xp without "running * off the top of the screen" so that you cannot copy the result. */ void output_monster_matlab(void) { int i, max, min; monster_race *r_ptr; char buf[2048], buf2[50]; unsigned int hp; FILE *fff; /* Create the file name */ path_build(buf, 500, ANGBAND_DIR_SAVE, "monmatlb.m"); /* Drop priv's */ safe_setuid_drop(); /* Open file */ fff = my_fopen(buf, "w"); /* Grab priv's */ safe_setuid_grab(); /* Failure */ if (!fff) return; /* Add starting stuff */ fprintf(fff, "xx=[];\n"); /* Min and max monsters to output in the matrix */ max = max_r_idx; min = 20; for (i = min; i < max; i++) { fprintf(fff, "x=["); /* Get race */ r_ptr = &r_info[i]; /* Hitpoints x2 */ hp = r_ptr->hdice * (r_ptr->hside + 1); if (r_ptr->flags1 & RF1_FORCE_MAXHP) { /* hp x2 */ hp = r_ptr->hdice * r_ptr->hside * 2; } /* Output the flags one by one */ outflagmatlab(r_ptr->flags1 & ~(0x00000020F), fff); outflagmatlab(r_ptr->flags2, fff); outflagmatlab(r_ptr->flags3, fff); outflagmatlab2(r_ptr->flags4, fff, hp); outflagmatlab2(r_ptr->flags5, fff, r_ptr->level); outflagmatlab2(r_ptr->flags6, fff, r_ptr->level); outflagmatlab2(r_ptr->flags8, fff, r_ptr->level); /* Numerical flags */ sprintf(buf2, "%d", r_ptr->speed); sprintf(buf2, "%s %d", buf2, hp); sprintf(buf2, "%s %d", buf2, r_ptr->aaf); sprintf(buf2, "%s %d", buf2, r_ptr->ac); sprintf(buf2, "%s %d", buf2, r_ptr->sleep); sprintf(buf2, "%s %d", buf2, r_ptr->freq_inate + r_ptr->freq_spell); /* The blows table */ outblowsmatlab(r_ptr, buf2); sprintf(buf2, "%s];\nxx=[xx;x];\n", buf2); fprintf(fff, "%s", buf2); } /* Output the power information */ fprintf(fff, "y=["); for (i = min; i < max; i++) { /* Get race */ r_ptr = &r_info[i]; /* Output the level */ sprintf(buf2, "%d ", monster_power_mat(r_ptr->level)); fprintf(fff, "%s", buf2); } fprintf(fff, "];\n"); /* Output the XP information */ fprintf(fff, "xp=["); for (i = min; i < max; i++) { /* Get race */ r_ptr = &r_info[i]; /* Output the experience for a kill */ sprintf(buf2, "%ld ", r_ptr->mexp); fprintf(fff, "%s", buf2); } fprintf(fff, "];"); my_fclose(fff); }
/* * Simple "main" function for multiple platforms. * * Note the special "--" option which terminates the processing of * standard options. All non-standard options (if any) are passed * directly to the "init_xxx()" function. */ int main(int argc, char *argv[]) { int i; bool done = FALSE; bool new_game = FALSE; int show_score = 0; cptr mstr = NULL; bool args = TRUE; /* Save the "program name" XXX XXX XXX */ argv0 = argv[0]; #ifdef USE_286 /* Attempt to use XMS (or EMS) memory for swap space */ if (_OvrInitExt(0L, 0L)) { _OvrInitEms(0, 0, 64); } #endif #ifdef SET_UID /* Default permissions on files */ (void)umask(022); # ifdef SECURE /* Authenticate */ Authenticate(); # endif #endif /* Get the file paths */ init_stuff(); #ifdef SET_UID /* Get the user id (?) */ player_uid = getuid(); #ifdef VMS /* Mega-Hack -- Factor group id */ player_uid += (getgid() * 1000); #endif # ifdef SAFE_SETUID # ifdef _POSIX_SAVED_IDS /* Save some info for later */ player_euid = geteuid(); player_egid = getegid(); # endif # if 0 /* XXX XXX XXX */ /* Redundant setting necessary in case root is running the game */ /* If not root or game not setuid the following two calls do nothing */ if (setgid(getegid()) != 0) { quit("setgid(): cannot set permissions correctly!"); } if (setuid(geteuid()) != 0) { quit("setuid(): cannot set permissions correctly!"); } # endif # endif #endif /* Drop permissions */ safe_setuid_drop(); #ifdef SET_UID /* Initialize the "time" checker */ if (check_time_init() || check_time()) { quit("The gates to Angband are closed (bad time)."); } /* Initialize the "load" checker */ if (check_load_init() || check_load()) { quit("The gates to Angband are closed (bad load)."); } /* Acquire the "user name" as a default player name */ user_name(player_name, player_uid); #ifdef PRIVATE_USER_PATH /* Create a directory for the users files. */ create_user_dir(); #endif /* PRIVATE_USER_PATH */ #endif /* SET_UID */ /* Process the command line arguments */ for (i = 1; args && (i < argc); i++) { /* Require proper options */ if (argv[i][0] != '-') goto usage; /* Analyze option */ switch (argv[i][1]) { case 'N': case 'n': { new_game = TRUE; break; } case 'F': case 'f': { arg_fiddle = TRUE; break; } case 'W': case 'w': { arg_wizard = TRUE; break; } case 'V': case 'v': { arg_sound = TRUE; break; } case 'G': case 'g': { /* HACK - Graphics mode switches on the original tiles */ arg_graphics = GRAPHICS_ORIGINAL; break; } case 'R': case 'r': { arg_force_roguelike = TRUE; break; } case 'O': case 'o': { arg_force_original = TRUE; break; } case 'S': case 's': { show_score = atoi(&argv[i][2]); if (show_score <= 0) show_score = 10; break; } case 'u': case 'U': { if (!argv[i][2]) goto usage; strcpy(player_name, &argv[i][2]); break; } case 'm': { if (!argv[i][2]) goto usage; mstr = &argv[i][2]; break; } case 'M': { arg_monochrome = TRUE; break; } case 'd': case 'D': { change_path(&argv[i][2]); break; } case '-': { argv[i] = argv[0]; argc = argc - i; argv = argv + i; args = FALSE; break; } default: usage: { /* Dump usage information */ puts("Usage: angband [options] [-- subopts]"); puts(" -n Start a new character"); puts(" -f Request fiddle mode"); puts(" -w Request wizard mode"); puts(" -v Request sound mode"); puts(" -g Request graphics mode"); puts(" -o Request original keyset"); puts(" -r Request rogue-like keyset"); puts(" -M Request monochrome mode"); puts(" -s<num> Show <num> high scores"); puts(" -u<who> Use your <who> savefile"); puts(" -m<sys> Force 'main-<sys>.c' usage"); puts(" -d<def> Define a 'lib' dir sub-path"); puts(""); #ifdef USE_SDL puts(" -msdl To use SDL"); #endif /* USE_SDL */ #ifdef USE_X11 puts(" -mx11 To use X11"); puts(" -- Sub options"); puts(" -- -d Set display name"); puts(" -- -o Request old 8x8 tile graphics"); puts(" -- -a Request Adam Bolt 16x16 tile graphics"); puts(" -- -b Request Bigtile graphics mode"); puts(" -- -s Turn off smoothscaling graphics"); puts(" -- -n# Number of terms to use"); puts(""); #endif /* USE_X11 */ #ifdef USE_GCU puts(" -mgcu To use GCU (GNU Curses)"); #endif /* USE_GCU */ #ifdef USE_CAP puts(" -mcap To use CAP (\"Termcap\" calls)"); #endif /* USE_CAP */ #ifdef USE_DOS puts(" -mdos To use DOS (Graphics)"); #endif /* USE_DOS */ #ifdef USE_IBM puts(" -mibm To use IBM (BIOS text mode)"); #endif /* USE_IBM */ #ifdef USE_SLA puts(" -msla To use SLA (SLANG)"); #endif /* USE_SLA */ #ifdef USE_LSL puts(" -mlsl To use LSL (Linux-SVGALIB)"); #endif /* USE_LSL */ #ifdef USE_AMI puts(" -mami To use AMI (Amiga)"); #endif /* USE_AMI */ #ifdef USE_VME puts(" -mvme To use VME (VAX/ESA)"); #endif /* USE_VME */ /* Actually abort the process */ quit(NULL); } } } /* Hack -- Forget standard args */ if (args) { argc = 1; argv[1] = NULL; } /* Process the player name */ process_player_name(TRUE); /* Create any missing directories */ create_needed_dirs(); /* Install "quit" hook */ quit_aux = quit_hook; #ifdef USE_XAW /* Attempt to use the "main-xaw.c" support */ if (!done && (!mstr || (streq(mstr, "xaw")))) { extern errr init_xaw(int, char**); if (0 == init_xaw(argc, argv)) { ANGBAND_SYS = "xaw"; done = TRUE; } } #endif #ifdef USE_SDL /* Attempt to use the "main-sdl.c" support */ if (!done && (!mstr || (streq(mstr, "sdl")))) { extern errr init_sdl(int, char**); if (0 == init_sdl(argc, argv)) { ANGBAND_SYS = "sdl"; done = TRUE; } } #endif #ifdef USE_X11 /* Attempt to use the "main-x11.c" support */ if (!done && (!mstr || (streq(mstr, "x11")))) { extern errr init_x11(int, char**); if (0 == init_x11(argc, argv)) { ANGBAND_SYS = "x11"; done = TRUE; } } #endif #ifdef USE_GCU /* Attempt to use the "main-gcu.c" support */ if (!done && (!mstr || (streq(mstr, "gcu")))) { extern errr init_gcu(int, char**); if (0 == init_gcu(argc, argv)) { ANGBAND_SYS = "gcu"; done = TRUE; } } #endif #ifdef USE_CAP /* Attempt to use the "main-cap.c" support */ if (!done && (!mstr || (streq(mstr, "cap")))) { extern errr init_cap(int, char**); if (0 == init_cap(argc, argv)) { ANGBAND_SYS = "cap"; done = TRUE; } } #endif #ifdef USE_DOS /* Attempt to use the "main-dos.c" support */ if (!done && (!mstr || (streq(mstr, "dos")))) { extern errr init_dos(void); if (0 == init_dos()) { ANGBAND_SYS = "dos"; done = TRUE; } } #endif #ifdef USE_IBM /* Attempt to use the "main-ibm.c" support */ if (!done && (!mstr || (streq(mstr, "ibm")))) { extern errr init_ibm(void); if (0 == init_ibm()) { ANGBAND_SYS = "ibm"; done = TRUE; } } #endif #ifdef USE_EMX /* Attempt to use the "main-emx.c" support */ if (!done && (!mstr || (streq(mstr, "emx")))) { extern errr init_emx(void); if (0 == init_emx()) { ANGBAND_SYS = "emx"; done = TRUE; } } #endif #ifdef USE_SLA /* Attempt to use the "main-sla.c" support */ if (!done && (!mstr || (streq(mstr, "sla")))) { extern errr init_sla(void); if (0 == init_sla()) { ANGBAND_SYS = "sla"; done = TRUE; } } #endif #ifdef USE_LSL /* Attempt to use the "main-lsl.c" support */ if (!done && (!mstr || (streq(mstr, "lsl")))) { extern errr init_lsl(void); if (0 == init_lsl()) { ANGBAND_SYS = "lsl"; done = TRUE; } } #endif #ifdef USE_AMI /* Attempt to use the "main-ami.c" support */ if (!done && (!mstr || (streq(mstr, "ami")))) { extern errr init_ami(void); if (0 == init_ami()) { ANGBAND_SYS = "ami"; done = TRUE; } } #endif #ifdef USE_VME /* Attempt to use the "main-vme.c" support */ if (!done && (!mstr || (streq(mstr, "vme")))) { extern errr init_vme(void); if (0 == init_vme()) { ANGBAND_SYS = "vme"; done = TRUE; } } #endif /* Make sure we have a display! */ if (!done) quit("Unable to prepare any 'display module'!"); /* Hack -- If requested, display scores and quit */ if (show_score > 0) display_scores(0, show_score); /* Catch nasty signals */ signals_init(); /* Initialize */ init_angband(); /* Wait for response */ pause_line(23); /* Play the game */ play_game(new_game); /* Quit */ quit(NULL); /* Exit */ return (0); }
/** * Actually place an entry into the high score file * Return the location (0 is best) or -1 on "failure" */ static void highscore_write(const high_score scores[], size_t sz) { size_t n; ang_file *lok; ang_file *scorefile; char old_name[1024]; char cur_name[1024]; char new_name[1024]; char lok_name[1024]; path_build(old_name, sizeof(old_name), ANGBAND_DIR_SCORES, "scores.old"); path_build(cur_name, sizeof(cur_name), ANGBAND_DIR_SCORES, "scores.raw"); path_build(new_name, sizeof(new_name), ANGBAND_DIR_SCORES, "scores.new"); path_build(lok_name, sizeof(lok_name), ANGBAND_DIR_SCORES, "scores.lok"); /* Read in and add new score */ n = highscore_count(scores, sz); /* Lock scores */ if (file_exists(lok_name)) { msg("Lock file in place for scorefile; not writing."); return; } safe_setuid_grab(); lok = file_open(lok_name, MODE_WRITE, FTYPE_RAW); file_lock(lok); safe_setuid_drop(); if (!lok) { msg("Failed to create lock for scorefile; not writing."); return; } /* Open the new file for writing */ safe_setuid_grab(); scorefile = file_open(new_name, MODE_WRITE, FTYPE_RAW); safe_setuid_drop(); if (!scorefile) { msg("Failed to open new scorefile for writing."); file_close(lok); file_delete(lok_name); return; } file_write(scorefile, (const char *)scores, sizeof(high_score)*n); file_close(scorefile); /* Now move things around */ safe_setuid_grab(); if (file_exists(old_name) && !file_delete(old_name)) msg("Couldn't delete old scorefile"); if (file_exists(cur_name) && !file_move(cur_name, old_name)) msg("Couldn't move old scores.raw out of the way"); if (!file_move(new_name, cur_name)) msg("Couldn't rename new scorefile to scores.raw"); /* Remove the lock */ file_close(lok); file_delete(lok_name); safe_setuid_drop(); }
/* * Attempt to Load a gamemode * * That is, load just enough of the save file to determine whether * we are playing Angband or Moria (and thus set game_mode) before * returning * */ void load_gamemode(void) { int fd = -1; errr err = 0; byte vvv[4]; byte savefile_game=0; /* Allow empty savefile name */ if (!savefile[0]) return; /* Okay */ if (!err) { /* Grab permissions */ safe_setuid_grab(); /* Open the savefile */ fff = file_open(savefile, MODE_READ, -1); if (fff) { fd = 0; } else fd = -1; /* Drop permissions */ safe_setuid_drop(); /* No file */ if (fd < 0) err = -1; } /* Process file */ if (!err) { /* Read the first four bytes */ if (!file_read(fff, (char*)(vvv), 4)) err = -1; rd_byte(&savefile_game); /* Close the file */ file_close(fff); } /* Need to clear checksums so they wont glitch out the real load */ xor_byte = 0; v_check = 0L; x_check = 0L; if (err) { return; } if (savefile_game == GAME_NPPMORIA) { game_mode = GAME_NPPMORIA; } else if (savefile_game == GAME_NPPANGBAND) { game_mode = GAME_NPPANGBAND; } return; }
/* * Attempt to save the player in a savefile */ bool savefile_save(const char *path) { ang_file *file; char new_savefile[1024]; char old_savefile[1024]; /* New savefile */ strnfmt(new_savefile, sizeof(new_savefile), "%s.new", path); strnfmt(old_savefile, sizeof(old_savefile), "%s.old", path); /* Make sure that the savefile doesn't already exist */ safe_setuid_grab(); file_delete(new_savefile); file_delete(old_savefile); safe_setuid_drop(); /* Open the savefile */ safe_setuid_grab(); file = file_open(new_savefile, MODE_WRITE, FTYPE_SAVE); safe_setuid_drop(); if (file) { file_write(file, (char *) &savefile_magic, 4); file_write(file, (char *) &savefile_name, 4); character_saved = try_save(file); file_close(file); } if (character_saved) { bool err = FALSE; safe_setuid_grab(); if (file_exists(savefile) && !file_move(savefile, old_savefile)) err = TRUE; if (!err) { if (!file_move(new_savefile, savefile)) err = TRUE; if (err) file_move(old_savefile, savefile); else file_delete(old_savefile); } safe_setuid_drop(); return err ? FALSE : TRUE; } /* Delete temp file */ safe_setuid_grab(); file_delete(new_savefile); safe_setuid_drop(); return FALSE; }
/* * Attempt to save the player in a savefile */ bool save_player(void) { int result = FALSE; char safe[1024]; // in final deployment versions, you cannot save in the tutorial if (DEPLOYMENT && p_ptr->game_type != 0) { return (FALSE); } /* New savefile */ my_strcpy(safe, savefile, sizeof(safe)); my_strcat(safe, ".new", sizeof(safe)); #ifdef VM /* Hack -- support "flat directory" usage on VM/ESA */ my_strcpy(safe, savefile, sizeof(safe)); my_strcat(safe, "n", sizeof(safe)); #endif /* VM */ /* Grab permissions */ safe_setuid_grab(); /* Remove it */ fd_kill(safe); /* Drop permissions */ safe_setuid_drop(); /* Attempt to save the player */ if (save_player_aux(safe)) { char temp[1024]; /* Old savefile */ my_strcpy(temp, savefile, sizeof(temp)); my_strcat(temp, ".old", sizeof(temp)); #ifdef VM /* Hack -- support "flat directory" usage on VM/ESA */ my_strcpy(temp, savefile, sizeof(temp)); my_strcat(temp, "o", sizeof(temp)); #endif /* VM */ /* Grab permissions */ safe_setuid_grab(); /* Remove it */ fd_kill(temp); /* Preserve old savefile */ fd_move(savefile, temp); /* Activate new savefile */ fd_move(safe, savefile); /* Remove preserved savefile */ fd_kill(temp); /* Drop permissions */ safe_setuid_drop(); /* Hack -- Pretend the character was loaded */ character_loaded = TRUE; #ifdef VERIFY_SAVEFILE /* Lock on savefile */ my_strcpy(temp, savefile, sizeof(temp)); my_strcat(temp, ".lok", sizeof(temp)); /* Grab permissions */ safe_setuid_grab(); /* Remove lock file */ fd_kill(temp); /* Drop permissions */ safe_setuid_drop(); #endif /* VERIFY_SAVEFILE */ /* Success */ result = TRUE; } /* Return the result */ return (result); }
/* * Attempt to Load a "savefile" * * On multi-user systems, you may only "read" a savefile if you will be * allowed to "write" it later, this prevents painful situations in which * the player loads a savefile belonging to someone else, and then is not * allowed to save his game when he quits. * * We return "TRUE" if the savefile was usable, and we set the global * flag "character_loaded" if a real, living, character was loaded. * * Note that we always try to load the "current" savefile, even if * there is no such file, so we must check for "empty" savefile names. */ bool load_player(void) { int fd = -1; errr err = 0; byte vvv[4]; byte savefile_game; cptr what = "generic"; /* Paranoia */ turn = 0; p_ptr->p_turn = 0; /* Paranoia */ p_ptr->is_dead = FALSE; load_player_ghost_file(); /* Allow empty savefile name */ if (!savefile[0]) return (TRUE); /* Grab permissions */ safe_setuid_grab(); /* Open the savefile */ fff = file_open(savefile, MODE_READ, -1); if (fff) fd = 0; else fd = -1; /* Drop permissions */ safe_setuid_drop(); /* No file */ if (fd < 0) { /* Give a message */ msg_print("Savefile does not exist."); message_flush(); /* Allow this */ return (TRUE); } /* Close the file */ file_close(fff); /* Okay */ if (!err) { /* Grab permissions */ safe_setuid_grab(); /* Open the savefile */ fff = file_open(savefile, MODE_READ, -1); if (fff) { fd = 0; } else fd = -1; /* Drop permissions */ safe_setuid_drop(); /* No file */ if (fd < 0) err = -1; /* Message (below) */ if (err) what = "Cannot open savefile"; } /* Process file */ if (!err) { /* Read the first four bytes */ if (!file_read(fff, (char*)(vvv), 4)) err = -1; /* What */ if (err) what = "Cannot read savefile"; rd_byte(&savefile_game); /* Close the file */ file_close(fff); } /* Process file */ if (!err) { /* Extract version */ sf_major = vvv[0]; sf_minor = vvv[1]; sf_patch = vvv[2]; sf_extra = vvv[3]; /* Clear screen */ Term_clear(); if (older_than(OLD_VERSION_MAJOR, OLD_VERSION_MINOR, OLD_VERSION_PATCH)) { err = -1; what = "Savefile is too old"; } else if (!older_than(VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH + 1)) { err = -1; what = "Savefile is from the future"; } else if (game_mode != savefile_game) { err = -1; if (game_mode == GAME_NPPMORIA) what = "Not a NPPMoria savefile"; else if (game_mode == GAME_NPPANGBAND) what = "Not a NPPAngband savefile"; else what = "Unknown savefile type"; } else { /* Attempt to load */ err = rd_savefile(); /* Message (below) */ if (err) what = "Cannot parse savefile"; } } /* Paranoia */ if (!err) { /* Invalid turn */ if (!turn) err = -1; /* Message (below) */ if (err) what = "Broken savefile"; } /* Okay */ if (!err) { /* Give a conversion warning */ if ((version_major != sf_major) || (version_minor != sf_minor) || (version_patch != sf_patch)) { /* Message */ msg_format("Converted a %d.%d.%d savefile.", sf_major, sf_minor, sf_patch); message_flush(); } /* Player is dead */ if (p_ptr->is_dead) { /*note, add or_true to the arg wixard if statement to resurrect character*/ /* Cheat death (unless the character retired) */ if (arg_wizard) { /*heal the player*/ hp_player(2000); /* Forget death */ p_ptr->is_dead = FALSE; /* A character was loaded */ character_loaded = TRUE; /* Done */ return (TRUE); } /* Forget death */ p_ptr->is_dead = FALSE; /* Count lives */ sf_lives++; /* Forget turns */ turn = 0; p_ptr->p_turn = 0; /* Done */ return (TRUE); } /* A character was loaded */ character_loaded = TRUE; /* Still alive */ if (p_ptr->chp >= 0) { /* Reset cause of death */ my_strcpy(p_ptr->died_from, "(alive and well)", sizeof(p_ptr->died_from)); } /* Success */ return (TRUE); } /* Message */ msg_format("Error (%s) reading %d.%d.%d savefile.", what, sf_major, sf_minor, sf_patch); message_flush(); /* Oops */ return (FALSE); }
/* * Attempt to Load a "savefile" * * On multi-user systems, you may only "read" a savefile if you will be * allowed to "write" it later, this prevents painful situations in which * the player loads a savefile belonging to someone else, and then is not * allowed to save his game when he quits. * * We return "TRUE" if the savefile was usable, and we set the global * flag "character_loaded" if a real, living, character was loaded. * * Note that we always try to load the "current" savefile, even if * there is no such file, so we must check for "empty" savefile names. */ bool load_player(void) { int fd = -1; errr err = 0; byte vvv[4]; #ifdef VERIFY_TIMESTAMP struct stat statbuf; #endif /* VERIFY_TIMESTAMP */ cptr what = "generic"; /* Paranoia */ turn = 0; /* Paranoia */ p_ptr->is_dead = FALSE; // Set a flag to show that we are restoring a game p_ptr->restoring = TRUE; /* Allow empty savefile name */ if (!savefile[0]) return (TRUE); /* Grab permissions */ safe_setuid_grab(); /* Open the savefile */ fd = fd_open(savefile, O_RDONLY); /* Drop permissions */ safe_setuid_drop(); /* No file */ if (fd < 0) { /* Give a message */ msg_format("Savefile \"%s\" does not exist.", savefile); message_flush(); /* Allow this */ p_ptr->restoring = FALSE; return (FALSE);//// } /* Close the file */ fd_close(fd); #ifdef VERIFY_SAVEFILE /* Verify savefile usage */ if (!err) { FILE *fkk; char temp[1024]; /* Extract name of lock file */ my_strcpy(temp, savefile, sizeof(temp)); my_strcat(temp, ".lok", sizeof(temp)); /* Grab permissions */ safe_setuid_grab(); /* Check for lock */ fkk = my_fopen(temp, "r"); /* Drop permissions */ safe_setuid_drop(); /* Oops, lock exists */ if (fkk) { /* Close the file */ my_fclose(fkk); /* Message */ msg_print("Savefile is currently in use."); message_flush(); /* Oops */ return (FALSE); } /* Grab permissions */ safe_setuid_grab(); /* Create a lock file */ fkk = my_fopen(temp, "w"); /* Drop permissions */ safe_setuid_drop(); /* Dump a line of info */ fprintf(fkk, "Lock file for savefile '%s'\n", savefile); /* Close the lock file */ my_fclose(fkk); } #endif /* VERIFY_SAVEFILE */ /* Okay */ if (!err) { /* Grab permissions */ safe_setuid_grab(); /* Open the savefile */ fd = fd_open(savefile, O_RDONLY); /* Drop permissions */ safe_setuid_drop(); /* No file */ if (fd < 0) err = -1; /* Message (below) */ if (err) what = "Cannot open savefile"; } /* Process file */ if (!err) { #ifdef VERIFY_TIMESTAMP /* Grab permissions */ safe_setuid_grab(); /* Get the timestamp */ (void)fstat(fd, &statbuf); /* Drop permissions */ safe_setuid_drop(); #endif /* VERIFY_TIMESTAMP */ /* Read the first four bytes */ if (fd_read(fd, (char*)(vvv), sizeof(vvv))) err = -1; /* What */ if (err) what = "Cannot read savefile"; /* Close the file */ fd_close(fd); } /* Process file */ if (!err) { /* Extract version */ sf_major = vvv[0]; sf_minor = vvv[1]; sf_patch = vvv[2]; sf_extra = vvv[3]; /* Clear screen */ Term_clear(); if (older_than(OLD_VERSION_MAJOR, OLD_VERSION_MINOR, OLD_VERSION_PATCH)) { err = -1; what = "Savefile is too old"; } else if (!older_than(VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH + 1)) { err = -1; what = "Savefile is from the future"; } else { /* Attempt to load */ err = rd_savefile(); /* Message (below) */ if (err) what = "Cannot parse savefile"; } } /* Paranoia */ if (!err) { /* Invalid turn */ if (!turn) err = -1; /* Message (below) */ if (err) what = "Broken savefile"; } #ifdef VERIFY_TIMESTAMP /* Verify timestamp */ if (!err && !arg_wizard) { /* Hack -- Verify the timestamp */ if (sf_when > (statbuf.st_ctime + 100) || sf_when < (statbuf.st_ctime - 100)) { /* Message */ what = "Invalid timestamp"; /* Oops */ err = -1; } } #endif /* VERIFY_TIMESTAMP */ /* Okay */ if (!err) { /* Give a conversion warning */ if ((version_major != sf_major) || (version_minor != sf_minor) || (version_patch != sf_patch)) { /* Message */ msg_format("Converted a %d.%d.%d savefile.", sf_major, sf_minor, sf_patch); message_flush(); } // if Morgoth has lost his crown... if ((&a_info[ART_MORGOTH_3])->cur_num == 1) { // lower Morgoth's protection, remove his light source, increase his will and perception (&r_info[R_IDX_MORGOTH])->pd -= 1; (&r_info[R_IDX_MORGOTH])->light = 0; (&r_info[R_IDX_MORGOTH])->wil += 5; (&r_info[R_IDX_MORGOTH])->per += 5; } /* Player is dead */ if (p_ptr->is_dead) { /* Cheat death (unless the character retired) */ if (arg_wizard) { /*heal the player*/ hp_player(100, TRUE, TRUE); /* Forget death */ p_ptr->is_dead = FALSE; /* A character was loaded */ character_loaded = TRUE; // put the character somewhere sensible p_ptr->depth = min_depth(); // Mark savefile p_ptr->noscore |= 0x0001; /* Done */ return (TRUE); } /* Forget death */ p_ptr->is_dead = FALSE; /* Count lives */ sf_lives++; /* Forget turns */ turn = 0; playerturn = 0; /* A dead character was loaded */ character_loaded_dead = TRUE;//// /* Done */ return (TRUE); } /* A character was loaded */ character_loaded = TRUE; /* Still alive */ if (p_ptr->chp >= 0) { /* Reset cause of death */ my_strcpy(p_ptr->died_from, "(alive and well)", sizeof (p_ptr->died_from)); } // count the artefacts seen for the player p_ptr->artefacts = artefact_count(); /* Success */ return (TRUE); } #ifdef VERIFY_SAVEFILE /* Verify savefile usage */ if (TRUE) { char temp[1024]; /* Extract name of lock file */ my_strcpy(temp, savefile, sizeof(temp)); my_strcat(temp, ".lok", sizeof(temp)); /* Grab permissions */ safe_setuid_grab(); /* Remove lock */ fd_kill(temp); /* Drop permissions */ safe_setuid_drop(); } #endif /* VERIFY_SAVEFILE */ /* Message */ msg_format("Error (%s) reading %d.%d.%d savefile.", what, sf_major, sf_minor, sf_patch); message_flush(); /* Oops */ return (FALSE); }
/* * Simple "main" function for multiple platforms. * * Note the special "--" option which terminates the processing of * standard options. All non-standard options (if any) are passed * directly to the "init_xxx()" function. */ int main(int argc, char *argv[]) { int i; bool done = FALSE; const char *mstr = NULL; const char *soundstr = NULL; bool args = TRUE; /* Save the "program name" XXX XXX XXX */ argv0 = argv[0]; #ifdef SET_UID /* Default permissions on files */ (void)umask(022); #endif /* SET_UID */ #ifdef SET_UID /* Get the user id */ player_uid = getuid(); /* Save the effective GID for later recall */ player_egid = getegid(); #endif /* SET_UID */ /* Drop permissions */ safe_setuid_drop(); /* Process the command line arguments */ for (i = 1; args && (i < argc); i++) { const char *arg = argv[i]; /* Require proper options */ if (*arg++ != '-') goto usage; /* Analyze option */ switch (*arg++) { case 'n': new_game = TRUE; break; case 'w': arg_wizard = TRUE; break; case 'r': arg_rebalance = TRUE; break; case 'g': /* Default graphics tile */ /* in graphics.txt, 2 corresponds to adam bolt's tiles */ arg_graphics = 2; if (*arg) arg_graphics = atoi(arg); break; case 'u': if (!*arg) goto usage; /* Get the savefile name */ my_strcpy(op_ptr->full_name, arg, sizeof(op_ptr->full_name)); continue; case 'm': if (!*arg) goto usage; mstr = arg; continue; case 's': if (!*arg) goto usage; soundstr = arg; continue; case 'd': change_path(arg); continue; case 'x': debug_opt(arg); continue; case '-': argv[i] = argv[0]; argc = argc - i; argv = argv + i; args = FALSE; break; default: usage: puts("Usage: angband [options] [-- subopts]"); puts(" -n Start a new character (WARNING: overwrites default savefile without -u)"); puts(" -w Resurrect dead character (marks savefile)"); puts(" -r Rebalance monsters"); puts(" -g Request graphics mode"); puts(" -x<opt> Debug options; see -xhelp"); puts(" -u<who> Use your <who> savefile"); puts(" -d<path> Store pref files and screendumps in <path>"); puts(" -s<mod> Use sound module <sys>:"); for (i = 0; i < (int)N_ELEMENTS(sound_modules); i++) printf(" %s %s\n", sound_modules[i].name, sound_modules[i].help); puts(" -m<sys> Use module <sys>, where <sys> can be:"); /* Print the name and help for each available module */ for (i = 0; i < (int)N_ELEMENTS(modules); i++) printf(" %s %s\n", modules[i].name, modules[i].help); /* Actually abort the process */ quit(NULL); } if (*arg) goto usage; } /* Hack -- Forget standard args */ if (args) { argc = 1; argv[1] = NULL; } /* Install "quit" hook */ quit_aux = quit_hook; /* If we were told which mode to use, then use it */ if (mstr) ANGBAND_SYS = mstr; if (setlocale(LC_CTYPE, "")) { /* Require UTF-8 */ if (strcmp(nl_langinfo(CODESET), "UTF-8") != 0) quit("Angband requires UTF-8 support"); } /* Get the file paths */ init_stuff(); /* Try the modules in the order specified by modules[] */ for (i = 0; i < (int)N_ELEMENTS(modules); i++) { /* User requested a specific module? */ if (!mstr || (streq(mstr, modules[i].name))) { ANGBAND_SYS = modules[i].name; if (0 == modules[i].init(argc, argv)) { done = TRUE; break; } } } /* Make sure we have a display! */ if (!done) quit("Unable to prepare any 'display module'!"); #ifdef SET_UID /* Get the "user name" as a default player name, unless set with -u switch */ if (!op_ptr->full_name[0]) { user_name(op_ptr->full_name, sizeof(op_ptr->full_name), player_uid); } /* Create any missing directories */ create_needed_dirs(); #endif /* SET_UID */ /* Process the player name */ process_player_name(TRUE); /* Try the modules in the order specified by sound_modules[] */ for (i = 0; i < (int)N_ELEMENTS(sound_modules); i++) if (!soundstr || streq(soundstr, sound_modules[i].name)) if (0 == sound_modules[i].init(argc, argv)) break; /* Catch nasty signals */ signals_init(); /* Set up the command hook */ cmd_get_hook = default_get_cmd; /* Set up the display handlers and things. */ init_display(); /* Play the game */ play_game(); /* Free resources */ cleanup_angband(); /* Quit */ quit(NULL); /* Exit */ return (0); }
/* * Simple "main" function for multiple platforms. * * Note the special "--" option which terminates the processing of * standard options. All non-standard options (if any) are passed * directly to the "init_xxx()" function. */ int main(int argc, char *argv[]) { int i; bool done = FALSE; bool new_game = FALSE; int show_score = 0; cptr mstr = NULL; bool args = TRUE; /* Save the "program name" XXX XXX XXX */ argv0 = argv[0]; #ifdef USE_286 /* Attempt to use XMS (or EMS) memory for swap space */ if (_OvrInitExt(0L, 0L)) { _OvrInitEms(0, 0, 64); } #endif #ifdef SET_UID /* Default permissions on files */ (void)umask(022); # ifdef SECURE /* Authenticate */ Authenticate(); # endif #endif /* Get the file paths */ init_stuff(); #ifdef SET_UID /* Get the user id (?) */ player_uid = getuid(); #ifdef VMS /* Mega-Hack -- Factor group id */ player_uid += (getgid() * 1000); #endif # ifdef SAFE_SETUID # ifdef _POSIX_SAVED_IDS /* Save some info for later */ player_euid = geteuid(); player_egid = getegid(); # endif # if 0 /* XXX XXX XXX */ /* Redundant setting necessary in case root is running the game */ /* If not root or game not setuid the following two calls do nothing */ if (setgid(getegid()) != 0) { quit("setgid(): cannot set permissions correctly!"); } if (setuid(geteuid()) != 0) { quit("setuid(): cannot set permissions correctly!"); } # endif # endif #endif #ifdef SET_UID /* Initialize the "time" checker */ if (check_time_init() || check_time()) { quit("The gates to Angband are closed (bad time)."); } /* Initialize the "load" checker */ if (check_load_init() || check_load()) { quit("The gates to Angband are closed (bad load)."); } /* Acquire the "user name" as a default player name */ #ifdef ANGBAND_2_8_1 user_name(player_name, player_uid); #else /* ANGBAND_2_8_1 */ user_name(op_ptr->full_name, player_uid); #endif /* ANGBAND_2_8_1 */ #ifdef PRIVATE_USER_PATH /* Create a directory for the users files. */ create_user_dir(); #endif /* PRIVATE_USER_PATH */ #endif /* SET_UID */ /* Process the command line arguments */ for (i = 1; args && (i < argc); i++) { /* Require proper options */ if (argv[i][0] != '-') game_usage(); /* Analyze option */ switch (argv[i][1]) { case 'N': case 'n': { new_game = TRUE; break; } case 'F': case 'f': { arg_fiddle = TRUE; break; } case 'W': case 'w': { arg_wizard = TRUE; break; } case 'V': case 'v': { arg_sound = TRUE; break; } case 'G': case 'g': { /* HACK - Graphics mode switches on the original tiles */ arg_graphics = GRAPHICS_ORIGINAL; break; } case 'R': case 'r': { arg_force_roguelike = TRUE; break; } case 'O': case 'o': { arg_force_original = TRUE; break; } case 'S': case 's': { show_score = atoi(&argv[i][2]); if (show_score <= 0) show_score = 10; break; } case 'u': case 'U': { if (!argv[i][2]) game_usage(); #ifdef ANGBAND_2_8_1 strncpy(player_name, &argv[i][2], 32); player_name[31] = '\0'; #else /* ANGBAND_2_8_1 */ strncpy(op_ptr->full_name, &argv[i][2], 32); op_ptr->full_name[31] = '\0'; #endif /* ANGBAND_2_8_1 */ break; } case 'm': { if (!argv[i][2]) game_usage(); mstr = &argv[i][2]; break; } case 'M': { arg_monochrome = TRUE; break; } case 'd': case 'D': { change_path(&argv[i][2]); break; } case '-': { argv[i] = argv[0]; argc = argc - i; argv = argv + i; args = FALSE; break; } default: { /* Default usage-help */ game_usage(); } } } /* Hack -- Forget standard args */ if (args) { argc = 1; argv[1] = NULL; } /* Process the player name */ process_player_name(TRUE); /* Install "quit" hook */ quit_aux = quit_hook; /* * Drop privs (so X11 will work correctly) * unless we are running the Linux-SVGALib version. * * (In which case we initialize after safe_setuid_grab() * is called.) */ safe_setuid_drop(); #ifdef USE_XAW /* Attempt to use the "main-xaw.c" support */ if (!done && (!mstr || (streq(mstr, "xaw")))) { if (0 == init_xaw(argc, argv)) { ANGBAND_SYS = "xaw"; done = TRUE; } } #endif #ifdef USE_X11 /* Attempt to use the "main-x11.c" support */ if (!done && (!mstr || (streq(mstr, "x11")))) { if (0 == init_x11(argc, argv)) { ANGBAND_SYS = "x11"; done = TRUE; } } #endif #ifdef USE_XPJ /* Attempt to use the "main-xpj.c" support */ if (!done && (!mstr || (streq(mstr, "xpj")))) { if (0 == init_xpj(argc, argv)) { ANGBAND_SYS = "xpj"; done = TRUE; } } #endif #ifdef USE_GTK /* Attempt to use the "main-gtk.c" support */ if (!done && (!mstr || (streq(mstr, "gtk")))) { if (0 == init_gtk((unsigned char*) &new_game, argc, argv)) { done = TRUE; } } #endif #ifdef USE_GCU /* Attempt to use the "main-gcu.c" support */ if (!done && (!mstr || (streq(mstr, "gcu")))) { if (0 == init_gcu()) { ANGBAND_SYS = "gcu"; done = TRUE; } } #endif #ifdef USE_CAP /* Attempt to use the "main-cap.c" support */ if (!done && (!mstr || (streq(mstr, "cap")))) { if (0 == init_cap(argc, argv)) { ANGBAND_SYS = "cap"; done = TRUE; } } #endif #ifdef USE_DOS /* Attempt to use the "main-dos.c" support */ if (!done && (!mstr || (streq(mstr, "dos")))) { if (0 == init_dos()) { ANGBAND_SYS = "dos"; done = TRUE; } } #endif #ifdef USE_IBM /* Attempt to use the "main-ibm.c" support */ if (!done && (!mstr || (streq(mstr, "ibm")))) { if (0 == init_ibm()) { ANGBAND_SYS = "ibm"; done = TRUE; } } #endif #ifdef USE_EMX /* Attempt to use the "main-emx.c" support */ if (!done && (!mstr || (streq(mstr, "emx")))) { if (0 == init_emx()) { ANGBAND_SYS = "emx"; done = TRUE; } } #endif #ifdef USE_SLA /* Attempt to use the "main-sla.c" support */ if (!done && (!mstr || (streq(mstr, "sla")))) { if (0 == init_sla()) { ANGBAND_SYS = "sla"; done = TRUE; } } #endif #ifdef USE_AMI /* Attempt to use the "main-ami.c" support */ if (!done && (!mstr || (streq(mstr, "ami")))) { if (0 == init_ami()) { ANGBAND_SYS = "ami"; done = TRUE; } } #endif #ifdef USE_VME /* Attempt to use the "main-vme.c" support */ if (!done && (!mstr || (streq(mstr, "vme")))) { if (0 == init_vme()) { ANGBAND_SYS = "vme"; done = TRUE; } } #endif #ifdef USE_VCS /* Attempt to use the "main-vcs.c" support */ if (!done && (!mstr || (streq(mstr, "vcs")))) { if (0 == init_vcs(argc, argv)) { ANGBAND_SYS = "vcs"; done = TRUE; } } #endif /* USE_VCS */ /* Grab privs (dropped above for X11) */ safe_setuid_grab(); #ifdef USE_LSL /* Attempt to use the "main-lsl.c" support */ if (!done && (!mstr || (streq(mstr, "lsl")))) { if (0 == init_lsl()) { ANGBAND_SYS = "lsl"; done = TRUE; } } #endif /* Make sure we have a display! */ if (!done) quit("Unable to prepare any 'display module'!"); /* Hack -- If requested, display scores and quit */ if (show_score > 0) display_scores(0, show_score); /* Gtk initializes earlier */ if (!streq(ANGBAND_SYS, "gtk")) { /* Catch nasty signals */ signals_init(); /* Initialize */ init_angband(); } /* Wait for response */ pause_line(23); /* Play the game */ play_game(new_game); /* Quit */ quit(NULL); /* Exit */ return (0); }
/* * Places a ghost somewhere. */ s16b place_ghost(void) { #if 0 /* DGDGDGDG */ int y, x, hp, level, grace, gclass; monster_race *r_ptr = &r_info[max_r_idx - 1]; FILE *fp; bool err = FALSE; bool town = FALSE; char name[100]; char tmp[1024]; /* Hack -- no ghosts in the town */ if (!dun_level) return (FALSE); /* Already have a ghost */ if (r_ptr->cur_num >= r_ptr->max_num) { return (FALSE); } /* Dungeon -- Use Dungeon Level */ else { /* And even then, it only happens sometimes */ if (14 > randint((dun_level / 2) + 11)) return (FALSE); /* Only a 45% chance */ if (magik(45)) return (FALSE); /* Level is dungeon level */ level = dun_level; } /* Choose a bones file */ sprintf(tmp, "%s%sbone%03d.%03d", ANGBAND_DIR_BONE, PATH_SEP, dungeon_type, level); /* Grab permission */ safe_setuid_grab(); /* Open the bones file */ fp = my_fopen(tmp, "r"); /* Drop permission */ safe_setuid_drop(); /* No bones file to use */ if (!fp) return (FALSE); /* Scan the file */ err = (fscanf(fp, "%[^\n]\n%d\n%d\n%d", name, &hp, &grace, &gclass) != 4); /* Close the file */ fclose(fp); /* Previously, the bone file would now be deleted. The new * method is to only remove the bone file when the ghost is * destroyed. This means that failing to kill a ghost will * not lose it permenently -TM- * fd_kill(tmp); */ /* Catch errors */ if (err) { msg_print("Warning -- deleted corrupt 'ghost' file!"); return (FALSE); } /* Create "town" flag */ /* TM- What is this? Previously, if the player and dungeon levels * were equal then a 'town' ghost was created. I can't see why * 'town'. They are simply ghosts with abilities determined by * previous class. Currently we just pick between the two. * WAS: if (level == p_ptr->lev) town = TRUE; */ if (!rand_int(2)) town = TRUE; /* Set up the ghost */ set_ghost(name, hp, grace, gclass, level, town); /* Hack -- pick a nice (far away) location */ while (1) { /* Pick a location */ y = randint(cur_hgt - 2); x = randint(cur_wid - 2); /* Require "naked" floor grid */ if (!cave_empty_bold(y, x)) continue; /* Accept far away grids */ if (distance(p_ptr->py, p_ptr->px, y, x) > MAX_SIGHT + 5) break; } /*** Place the Ghost by Hand (so no-one else does it accidentally) ***/ r_ptr->cur_num = 0; r_ptr->max_num = 1; if (!place_monster_one(y, x, max_r_idx - 1, 0, FALSE, MSTATUS_ENEMY)) { return FALSE; } /* Make sure it looks right */ r_ptr->x_attr = r_ptr->d_attr; r_ptr->x_char = r_ptr->d_char; return TRUE; #else return (FALSE); #endif }
/** * Simple "main" function for multiple platforms. * * Note the special "--" option which terminates the processing of * standard options. All non-standard options (if any) are passed * directly to the "init_xxx()" function. */ int main(int argc, char *argv[]) { int i; bool done = FALSE; const char *mstr = NULL; const char *soundstr = NULL; bool args = TRUE; /* Save the "program name" XXX XXX XXX */ argv0 = argv[0]; #ifdef UNIX /* Default permissions on files */ (void)umask(022); /* Get the user id */ player_uid = getuid(); #endif /* UNIX */ #ifdef SETGID /* Save the effective GID for later recall */ player_egid = getegid(); #endif /* UNIX */ /* Drop permissions */ safe_setuid_drop(); /* Get the file paths * Paths may be overriden by -d options, so this has to occur *before* * processing command line args */ init_stuff(); /* Process the command line arguments */ for (i = 1; args && (i < argc); i++) { const char *arg = argv[i]; /* Require proper options */ if (*arg++ != '-') goto usage; /* Analyze option */ switch (*arg++) { case 'l': list_saves(); exit(0); case 'n': new_game = TRUE; break; case 'w': arg_wizard = TRUE; break; case 'p': arg_power = TRUE; break; case 'r': arg_rebalance = TRUE; break; case 'g': /* Default graphics tile */ /* in graphics.txt, 2 corresponds to adam bolt's tiles */ arg_graphics = 2; if (*arg) arg_graphics = atoi(arg); break; case 'u': { if (!*arg) goto usage; my_strcpy(op_ptr->full_name, arg, sizeof op_ptr->full_name); /* The difference here is because on setgid we have to be * careful to only let the player have savefiles stored in * the central save directory. Sanitising input using * player_safe_name() removes anything like that. * * But if the player is running with per-user saves, they * can do whatever the hell they want. */ #ifdef SETGID savefile_set_name(player_safe_name(player, FALSE)); #else savefile_set_name(arg); #endif /* SETGID */ continue; } case 'm': if (!*arg) goto usage; mstr = arg; continue; case 's': if (!*arg) goto usage; soundstr = arg; continue; case 'd': change_path(arg); continue; case 'x': debug_opt(arg); continue; case '-': argv[i] = argv[0]; argc = argc - i; argv = argv + i; args = FALSE; break; default: usage: puts("Usage: angband [options] [-- subopts]"); puts(" -n Start a new character (WARNING: overwrites default savefile without -u)"); puts(" -l Lists all savefiles you can play"); puts(" -w Resurrect dead character (marks savefile)"); puts(" -r Rebalance monsters"); puts(" -g Request graphics mode"); puts(" -x<opt> Debug options; see -xhelp"); puts(" -u<who> Use your <who> savefile"); puts(" -d<dir>=<path> Override a specific directory with <path>. <path> can be:"); for (i = 0; i < (int)N_ELEMENTS(change_path_values); i++) { #ifdef SETGID if (!change_path_values[i].setgid_ok) continue; #endif printf(" %s (default is %s)\n", change_path_values[i].name, *change_path_values[i].path); } puts(" Multiple -d options are allowed."); puts(" -s<mod> Use sound module <sys>:"); for (i = 0; i < (int)N_ELEMENTS(sound_modules); i++) printf(" %s %s\n", sound_modules[i].name, sound_modules[i].help); puts(" -m<sys> Use module <sys>, where <sys> can be:"); /* Print the name and help for each available module */ for (i = 0; i < (int)N_ELEMENTS(modules); i++) printf(" %s %s\n", modules[i].name, modules[i].help); /* Actually abort the process */ quit(NULL); } if (*arg) goto usage; } /* Hack -- Forget standard args */ if (args) { argc = 1; argv[1] = NULL; } /* Install "quit" hook */ quit_aux = quit_hook; /* If we were told which mode to use, then use it */ if (mstr) ANGBAND_SYS = mstr; if (setlocale(LC_CTYPE, "")) { /* Require UTF-8 */ if (strcmp(nl_langinfo(CODESET), "UTF-8") != 0) quit("Angband requires UTF-8 support"); } /* Try the modules in the order specified by modules[] */ for (i = 0; i < (int)N_ELEMENTS(modules); i++) { /* User requested a specific module? */ if (!mstr || (streq(mstr, modules[i].name))) { ANGBAND_SYS = modules[i].name; if (0 == modules[i].init(argc, argv)) { done = TRUE; break; } } } /* Make sure we have a display! */ if (!done) quit("Unable to prepare any 'display module'!"); #ifdef UNIX /* Get the "user name" as default player name, unless set with -u switch */ if (!op_ptr->full_name[0]) { user_name(op_ptr->full_name, sizeof(op_ptr->full_name), player_uid); /* Set the savefile to load */ savefile_set_name(player_safe_name(player, FALSE)); } /* Create any missing directories */ create_needed_dirs(); #endif /* UNIX */ /* Try the modules in the order specified by sound_modules[] */ for (i = 0; i < (int)N_ELEMENTS(sound_modules); i++) if (!soundstr || streq(soundstr, sound_modules[i].name)) if (0 == sound_modules[i].init(argc, argv)) break; /* Catch nasty signals */ signals_init(); /* Set up the command hook */ cmd_get_hook = textui_get_cmd; /* Set up the display handlers and things. */ init_display(); init_angband(); textui_init(); /* Wait for response */ pause_line(Term); /* Play the game */ play_game(new_game); /* Free resources */ textui_cleanup(); cleanup_angband(); /* Quit */ quit(NULL); /* Exit */ return (0); }
/* * Enters a players name on a hi-score table, if "legal", and in any * case, displays some relevant portion of the high score list. * * Assumes "signals_ignore_tstp()" has been called. */ errr top_twenty(void) { int j; high_score the_score; time_t ct = time((time_t*)0); errr err; /* Clear the record */ (void)WIPE(&the_score, high_score); /* Save the version */ sprintf(the_score.what, "%u.%u.%u", VER_MAJOR, VER_MINOR, VER_PATCH); /* Calculate and save the points */ sprintf(the_score.pts, "%9ld", (long)total_points()); the_score.pts[9] = '\0'; /* Save the current gold */ sprintf(the_score.gold, "%9d", p_ptr->au); the_score.gold[9] = '\0'; /* Save the current turn */ sprintf(the_score.turns, "%9d", turn_real(turn)); the_score.turns[9] = '\0'; #ifdef HIGHSCORE_DATE_HACK /* Save the date in a hacked up form (9 chars) */ (void)sprintf(the_score.day, "%-.6s %-.2s", ctime(&ct) + 4, ctime(&ct) + 22); #else /* Save the date in standard form (8 chars) */ /* (void)strftime(the_score.day, 9, "%m/%d/%y", localtime(&ct)); */ /* Save the date in standard encoded form (9 chars) */ strftime(the_score.day, 10, "@%Y%m%d", localtime(&ct)); #endif /* Save the player name (15 chars) */ sprintf(the_score.who, "%-.15s", player_name); /* Save the player info XXX XXX XXX */ sprintf(the_score.uid, "%7u", player_uid); sprintf(the_score.sex, "%c", (p_ptr->psex ? 'm' : 'f')); sprintf(the_score.p_r, "%2d", p_ptr->prace); sprintf(the_score.p_c, "%2d", p_ptr->pclass); sprintf(the_score.p_a, "%2d", p_ptr->personality); /* Save the level and such */ sprintf(the_score.cur_lev, "%3d", p_ptr->lev); sprintf(the_score.cur_dun, "%3d", dun_level); sprintf(the_score.max_lev, "%3d", p_ptr->max_plv); sprintf(the_score.max_dun, "%3d", max_dlv[dungeon_type]); /* Save the cause of death (31 chars) */ if (strlen(p_ptr->died_from) >= sizeof(the_score.how)) { my_strcpy(the_score.how, p_ptr->died_from, sizeof(the_score.how) - 3); strcat(the_score.how, "..."); } else { strcpy(the_score.how, p_ptr->died_from); } /* Grab permissions */ safe_setuid_grab(); /* Lock (for writing) the highscore file, or fail */ err = fd_lock(highscore_fd, F_WRLCK); /* Drop permissions */ safe_setuid_drop(); if (err) return (1); /* Add a new entry to the score list, see where it went */ j = highscore_add(&the_score); /* Grab permissions */ safe_setuid_grab(); /* Unlock the highscore file, or fail */ err = fd_lock(highscore_fd, F_UNLCK); /* Drop permissions */ safe_setuid_drop(); if (err) return (1); /* Hack -- Display the top fifteen scores */ if (j < 10) { display_scores_aux(0, 15, j, NULL); } /* Display the scores surrounding the player */ else { display_scores_aux(0, 5, j, NULL); display_scores_aux(j - 2, j + 7, j, NULL); } /* Success */ return (0); }
/*! * @brief 保存フロア配列を初期化する / Initialize saved_floors array. * @param force テンポラリファイルが残っていた場合も警告なしで強制的に削除する。 * @details Make sure that old temporal files are not remaining as gurbages. * @return なし */ void init_saved_floors(bool force) { char floor_savefile[1024]; int i; int fd = -1; BIT_FLAGS mode = 0644; #ifdef SET_UID # ifdef SECURE /* Get "games" permissions */ beGames(); # endif #endif for (i = 0; i < MAX_SAVED_FLOORS; i++) { saved_floor_type *sf_ptr = &saved_floors[i]; /* File name */ sprintf(floor_savefile, "%s.F%02d", savefile, i); /* Grab permissions */ safe_setuid_grab(); /* Try to create the file */ fd = fd_make(floor_savefile, mode); /* Drop permissions */ safe_setuid_drop(); /* Failed! */ if (fd < 0) { if (!force) { #ifdef JP msg_print("エラー:古いテンポラリ・ファイルが残っています。"); msg_print("短愚蛮怒を二重に起動していないか確認してください。"); msg_print("過去に短愚蛮怒がクラッシュした場合は一時ファイルを"); msg_print("強制的に削除して実行を続けられます。"); if (!get_check("強制的に削除してもよろしいですか?")) quit("実行中止"); #else msg_print("Error: There are old temporal files."); msg_print("Make sure you are not running two game processes simultaneously."); msg_print("If the temporal files are garbages of old crashed process, "); msg_print("you can delete it safely."); if (!get_check("Do you delete old temporal files? ")) quit("Aborted."); #endif force = TRUE; } } else { /* Close the "fd" */ (void)fd_close(fd); } /* Grab permissions */ safe_setuid_grab(); /* Simply kill the temporal file */ (void)fd_kill(floor_savefile); /* Drop permissions */ safe_setuid_drop(); sf_ptr->floor_id = 0; } /* No floor_id used yet (No.0 is reserved to indicate non existance) */ max_floor_id = 1; /* vist_mark is from 1 */ latest_visit_mark = 1; /* A sign to mark temporal files */ saved_floor_file_sign = (u32b)time(NULL); /* No next floor yet */ new_floor_id = 0; /* No change floor mode yet */ change_floor_mode = 0; #ifdef SET_UID # ifdef SECURE /* Drop "games" permissions */ bePlayer(); # endif #endif }
/*! * @brief セーブデータ書き込みのサブルーチン / * Medium level player saver * @return 成功すればtrue * @details * XXX XXX XXX Angband 2.8.0 will use "fd" instead of "fff" if possible */ static bool save_player_aux(char *name) { bool ok = FALSE; int fd = -1; int mode = 0644; /* No file yet */ fff = NULL; /* File type is "SAVE" */ FILE_TYPE(FILE_TYPE_SAVE); /* Grab permissions */ safe_setuid_grab(); /* Create the savefile */ fd = fd_make(name, mode); /* Drop permissions */ safe_setuid_drop(); /* File is okay */ if (fd >= 0) { /* Close the "fd" */ (void)fd_close(fd); /* Grab permissions */ safe_setuid_grab(); /* Open the savefile */ fff = my_fopen(name, "wb"); /* Drop permissions */ safe_setuid_drop(); /* Successful open */ if (fff) { /* Write the savefile */ if (wr_savefile_new()) ok = TRUE; /* Attempt to close it */ if (my_fclose(fff)) ok = FALSE; } /* Grab permissions */ safe_setuid_grab(); /* Remove "broken" files */ if (!ok) (void)fd_kill(name); /* Drop permissions */ safe_setuid_drop(); } /* Failure */ if (!ok) return (FALSE); counts_write(0, playtime); /* Successful save */ character_saved = TRUE; /* Success */ return (TRUE); }
/*! * @brief セーブデータ書き込みのメインルーチン / * Attempt to save the player in a savefile * @return 成功すればtrue */ bool save_player(void) { int result = FALSE; char safe[1024]; #ifdef SET_UID # ifdef SECURE /* Get "games" permissions */ beGames(); # endif #endif /* New savefile */ strcpy(safe, savefile); strcat(safe, ".new"); #ifdef VM /* Hack -- support "flat directory" usage on VM/ESA */ strcpy(safe, savefile); strcat(safe, "n"); #endif /* VM */ /* Grab permissions */ safe_setuid_grab(); /* Remove it */ fd_kill(safe); /* Drop permissions */ safe_setuid_drop(); update_playtime(); /* Attempt to save the player */ if (save_player_aux(safe)) { char temp[1024]; /* Old savefile */ strcpy(temp, savefile); strcat(temp, ".old"); #ifdef VM /* Hack -- support "flat directory" usage on VM/ESA */ strcpy(temp, savefile); strcat(temp, "o"); #endif /* VM */ /* Grab permissions */ safe_setuid_grab(); /* Remove it */ fd_kill(temp); /* Preserve old savefile */ fd_move(savefile, temp); /* Activate new savefile */ fd_move(safe, savefile); /* Remove preserved savefile */ fd_kill(temp); /* Drop permissions */ safe_setuid_drop(); /* Hack -- Pretend the character was loaded */ character_loaded = TRUE; #ifdef VERIFY_SAVEFILE /* Lock on savefile */ strcpy(temp, savefile); strcat(temp, ".lok"); /* Grab permissions */ safe_setuid_grab(); /* Remove lock file */ fd_kill(temp); /* Drop permissions */ safe_setuid_drop(); #endif /* Success */ result = TRUE; } #ifdef SET_UID # ifdef SECURE /* Drop "games" permissions */ bePlayer(); # endif #endif /* Return the result */ return (result); }
/* * Attempt to Load a "savefile" * * On multi-user systems, you may only "read" a savefile if you will be * allowed to "write" it later, this prevents painful situations in which * the player loads a savefile belonging to someone else, and then is not * allowed to save his game when he quits. * * We return "TRUE" if the savefile was usable, and we set the global * flag "character_loaded" if a real, living, character was loaded. * * Note that we always try to load the "current" savefile, even if * there is no such file, so we must check for "empty" savefile names. */ bool load_player(void) { int fd = -1; errr err = 0; byte vvv[4]; #ifdef VERIFY_TIMESTAMP struct stat statbuf; #endif /* VERIFY_TIMESTAMP */ cptr what = "generic"; /* Paranoia */ turn = 0; /* Paranoia */ p_ptr->is_dead = FALSE; /* Allow empty savefile name */ if (!savefile[0]) return (TRUE); /* Grab permissions */ safe_setuid_grab(); /* Open the savefile */ fd = fd_open(savefile, O_RDONLY); /* Drop permissions */ safe_setuid_drop(); /* No file */ if (fd < 0) { /* Give a message */ msg_print("Savefile does not exist."); message_flush(); /* Allow this */ return (TRUE); } /* Close the file */ fd_close(fd); #ifdef VERIFY_SAVEFILE /* Verify savefile usage */ if (!err) { FILE *fkk; char temp[1024]; /* Extract name of lock file */ strcpy(temp, savefile); strcat(temp, ".lok"); /* Grab permissions */ safe_setuid_grab(); /* Check for lock */ fkk = my_fopen(temp, "r"); /* Drop permissions */ safe_setuid_drop(); /* Oops, lock exists */ if (fkk) { /* Close the file */ my_fclose(fkk); /* Message */ msg_print("Savefile is currently in use."); message_flush(); /* Oops */ return (FALSE); } /* Grab permissions */ safe_setuid_grab(); /* Create a lock file */ fkk = my_fopen(temp, "w"); /* Drop permissions */ safe_setuid_drop(); /* Dump a line of info */ fprintf(fkk, "Lock file for savefile '%s'\n", savefile); /* Close the lock file */ my_fclose(fkk); } #endif /* VERIFY_SAVEFILE */ /* Okay */ if (!err) { /* Grab permissions */ safe_setuid_grab(); /* Open the savefile */ fd = fd_open(savefile, O_RDONLY); /* Drop permissions */ safe_setuid_drop(); /* No file */ if (fd < 0) err = -1; /* Message (below) */ if (err) what = "Cannot open savefile"; } /* Process file */ if (!err) { #ifdef VERIFY_TIMESTAMP /* Grab permissions */ safe_setuid_grab(); /* Get the timestamp */ (void)fstat(fd, &statbuf); /* Drop permissions */ safe_setuid_drop(); #endif /* VERIFY_TIMESTAMP */ /* Read the first four bytes */ if (fd_read(fd, (char*)(vvv), sizeof(vvv))) err = -1; /* What */ if (err) what = "Cannot read savefile"; /* Close the file */ fd_close(fd); } /* Process file */ if (!err) { /* Extract version */ sf_major = vvv[0]; sf_minor = vvv[1]; sf_patch = vvv[2]; sf_extra = vvv[3]; /* Clear screen */ Term_clear(); if (older_than(OLD_VERSION_MAJOR, OLD_VERSION_MINOR, OLD_VERSION_PATCH)) { err = -1; what = "Savefile is too old"; } else if (!older_than(VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH + 1)) { err = -1; what = "Savefile is from the future"; } else { /* Attempt to load */ err = rd_savefile(); /* Message (below) */ if (err) what = "Cannot parse savefile"; } } /* Paranoia */ if (!err) { /* Invalid turn */ if (!turn) err = -1; /* Message (below) */ if (err) what = "Broken savefile"; } #ifdef VERIFY_TIMESTAMP /* Verify timestamp */ if (!err && !arg_wizard) { /* Hack -- Verify the timestamp */ if (sf_when > (statbuf.st_ctime + 100) || sf_when < (statbuf.st_ctime - 100)) { /* Message */ what = "Invalid timestamp"; /* Oops */ err = -1; } } #endif /* VERIFY_TIMESTAMP */ /* Okay */ if (!err) { /* Give a conversion warning */ if ((version_major != sf_major) || (version_minor != sf_minor) || (version_patch != sf_patch)) { /* Message */ msg_format("Converted a %d.%d.%d savefile.", sf_major, sf_minor, sf_patch); message_flush(); } /* Player is dead */ if (p_ptr->is_dead) { /* Forget death */ p_ptr->is_dead = FALSE; /* Cheat death */ if (arg_wizard) { /* A character was loaded */ character_loaded = TRUE; /* Done */ return (TRUE); } /* Count lives */ sf_lives++; /* Forget turns */ turn = old_turn = 0; /* Done */ return (TRUE); } /* A character was loaded */ character_loaded = TRUE; /* Still alive */ if (p_ptr->chp >= 0) { /* Reset cause of death */ strcpy(p_ptr->died_from, "(alive and well)"); } /* Success */ return (TRUE); } #ifdef VERIFY_SAVEFILE /* Verify savefile usage */ if (TRUE) { char temp[1024]; /* Extract name of lock file */ strcpy(temp, savefile); strcat(temp, ".lok"); /* Grab permissions */ safe_setuid_grab(); /* Remove lock */ fd_kill(temp); /* Drop permissions */ safe_setuid_drop(); } #endif /* VERIFY_SAVEFILE */ /* Message */ msg_format("Error (%s) reading %d.%d.%d savefile.", what, sf_major, sf_minor, sf_patch); message_flush(); /* Oops */ return (FALSE); }
/*! * @brief ゲームプレイ中のフロア一時保存出力処理メインルーチン / Attempt to save the temporally saved-floor data * @param sf_ptr 保存フロア参照ポインタ * @param mode 保存オプション * @return なし */ bool save_floor(saved_floor_type *sf_ptr, u32b mode) { FILE *old_fff = NULL; byte old_xor_byte = 0; u32b old_v_stamp = 0; u32b old_x_stamp = 0; char floor_savefile[1024]; int fd = -1; bool ok = FALSE; if (!(mode & SLF_SECOND)) { #ifdef SET_UID # ifdef SECURE /* Get "games" permissions */ beGames(); # endif #endif } /* We have one file already opened */ else { /* Backup original values */ old_fff = fff; old_xor_byte = xor_byte; old_v_stamp = v_stamp; old_x_stamp = x_stamp; } /* New savefile */ sprintf(floor_savefile, "%s.F%02d", savefile, (int)sf_ptr->savefile_id); /* Grab permissions */ safe_setuid_grab(); /* Remove it */ fd_kill(floor_savefile); /* Drop permissions */ safe_setuid_drop(); /* Attempt to save the player */ /* No file yet */ fff = NULL; /* File type is "SAVE" */ FILE_TYPE(FILE_TYPE_SAVE); /* Grab permissions */ safe_setuid_grab(); /* Create the savefile */ fd = fd_make(floor_savefile, 0644); /* Drop permissions */ safe_setuid_drop(); /* File is okay */ if (fd >= 0) { /* Close the "fd" */ (void)fd_close(fd); /* Grab permissions */ safe_setuid_grab(); /* Open the savefile */ fff = my_fopen(floor_savefile, "wb"); /* Drop permissions */ safe_setuid_drop(); /* Successful open */ if (fff) { /* Write the savefile */ if (save_floor_aux(sf_ptr)) ok = TRUE; /* Attempt to close it */ if (my_fclose(fff)) ok = FALSE; } /* Remove "broken" files */ if (!ok) { /* Grab permissions */ safe_setuid_grab(); (void)fd_kill(floor_savefile); /* Drop permissions */ safe_setuid_drop(); } } if (!(mode & SLF_SECOND)) { #ifdef SET_UID # ifdef SECURE /* Drop "games" permissions */ bePlayer(); # endif #endif } /* We have one file already opened */ else { /* Restore original values */ fff = old_fff; xor_byte = old_xor_byte; v_stamp = old_v_stamp; x_stamp = old_x_stamp; } /* Return the result */ return ok; }
/* * Attempt to save the player in a savefile */ bool savefile_save(const char *path) { ang_file *file; int count = 0; char new_savefile[1024]; char old_savefile[1024]; /* New savefile */ strnfmt(old_savefile, sizeof(old_savefile), "%s%u.old", path,Rand_simple(1000000)); while (file_exists(old_savefile) && (count++ < 100)) { strnfmt(old_savefile, sizeof(old_savefile), "%s%u%u.old", path,Rand_simple(1000000),count); } count = 0; /* Make sure that the savefile doesn't already exist */ /*safe_setuid_grab(); file_delete(new_savefile); file_delete(old_savefile); safe_setuid_drop();*/ /* Open the savefile */ safe_setuid_grab(); strnfmt(new_savefile, sizeof(new_savefile), "%s%u.new", path,Rand_simple(1000000)); while (file_exists(new_savefile) && (count++ < 100)) { strnfmt(new_savefile, sizeof(new_savefile), "%s%u%u.new", path,Rand_simple(1000000),count); } file = file_open(new_savefile, MODE_WRITE, FTYPE_SAVE); safe_setuid_drop(); if (file) { file_write(file, (char *) &savefile_magic, 4); file_write(file, (char *) &savefile_name, 4); character_saved = try_save(file); file_close(file); } if (character_saved) { bool err = FALSE; safe_setuid_grab(); if (file_exists(savefile) && !file_move(savefile, old_savefile)) err = TRUE; if (!err) { if (!file_move(new_savefile, savefile)) err = TRUE; if (err) file_move(old_savefile, savefile); else file_delete(old_savefile); } safe_setuid_drop(); return err ? FALSE : TRUE; } /* Delete temp file if the save failed */ if (file) { /* file is no longer valid, but it still points to a non zero * value if the file was created above */ safe_setuid_grab(); file_delete(new_savefile); safe_setuid_drop(); } return FALSE; }
/* * Initialize a "*_info" array * * Note that we let each entry have a unique "name" and "text" string, * even if the string happens to be empty (everyone has a unique '\0'). */ static errr init_info(cptr filename, header *head) { int fd; errr err = 1; FILE *fp; /* General buffer */ char buf[1024]; #ifdef ALLOW_TEMPLATES /*** Load the binary image file ***/ /* Build the filename */ path_build(buf, sizeof(buf), ANGBAND_DIR_DATA, format("%s.raw", filename)); /* Attempt to open the "raw" file */ fd = fd_open(buf, O_RDONLY); /* Process existing "raw" file */ if (fd >= 0) { #ifdef CHECK_MODIFICATION_TIME err = check_modification_date(fd, format("%s.txt", filename)); #endif /* CHECK_MODIFICATION_TIME */ /* Attempt to parse the "raw" file */ if (!err) err = init_info_raw(fd, head); /* Close it */ fd_close(fd); } /* Do we have to parse the *.txt file? */ if (err) { /*** Make the fake arrays ***/ /* Allocate the "*_info" array */ C_MAKE(head->info_ptr, head->info_size, char); /* MegaHack -- make "fake" arrays */ if (z_info) { C_MAKE(head->name_ptr, z_info->fake_name_size, char); C_MAKE(head->text_ptr, z_info->fake_text_size, char); } /*** Load the ascii template file ***/ /* Build the filename */ path_build(buf, sizeof(buf), ANGBAND_DIR_EDIT, format("%s.txt", filename)); /* Open the file */ fp = my_fopen(buf, "r"); /* Parse it */ if (!fp) quit(format("Cannot open '%s.txt' file.", filename)); /* Parse the file */ err = init_info_txt(fp, buf, head, head->parse_info_txt); /* Close it */ my_fclose(fp); /* Errors */ if (err) display_parse_error(filename, err, buf); /*** Dump the binary image file ***/ /* File type is "DATA" */ FILE_TYPE(FILE_TYPE_DATA); /* Build the filename */ path_build(buf, sizeof(buf), ANGBAND_DIR_DATA, format("%s.raw", filename)); /* Attempt to open the file */ fd = fd_open(buf, O_RDONLY); /* Failure */ if (fd < 0) { int mode = 0644; /* Grab permissions */ safe_setuid_grab(); /* Create a new file */ fd = fd_make(buf, mode); /* Drop permissions */ safe_setuid_drop(); /* Failure */ if (fd < 0) { char why[1024]; /* Message */ strnfmt(why, sizeof(why), "Cannot create the '%s' file!", buf); /* Crash and burn */ quit(why); } } /* Close it */ fd_close(fd); /* Grab permissions */ safe_setuid_grab(); /* Attempt to create the raw file */ fd = fd_open(buf, O_WRONLY); /* Drop permissions */ safe_setuid_drop(); /* Dump to the file */ if (fd >= 0) { /* Dump it */ fd_write(fd, (cptr)head, head->head_size); /* Dump the "*_info" array */ fd_write(fd, head->info_ptr, head->info_size); /* Dump the "*_name" array */ fd_write(fd, head->name_ptr, head->name_size); /* Dump the "*_text" array */ fd_write(fd, head->text_ptr, head->text_size); /* Close */ fd_close(fd); } /*** Kill the fake arrays ***/ /* Free the "*_info" array */ KILL(head->info_ptr); /* MegaHack -- Free the "fake" arrays */ if (z_info) { KILL(head->name_ptr); KILL(head->text_ptr); } #endif /* ALLOW_TEMPLATES */ /*** Load the binary image file ***/ /* Build the filename */ path_build(buf, sizeof(buf), ANGBAND_DIR_DATA, format("%s.raw", filename)); /* Attempt to open the "raw" file */ fd = fd_open(buf, O_RDONLY); /* Process existing "raw" file */ if (fd < 0) quit(format("Cannot load '%s.raw' file.", filename)); /* Attempt to parse the "raw" file */ err = init_info_raw(fd, head); /* Close it */ fd_close(fd); /* Error */ if (err) quit(format("Cannot parse '%s.raw' file.", filename)); #ifdef ALLOW_TEMPLATES } #endif /* ALLOW_TEMPLATES */ /* Success */ return (0); }