Angband 3.0.9b.
[angband.git] / src / save.c
blobbad7d26accdcbc1e51f80a5c0abe39fba1146158
1 /* File: save.c */
3 /*
4 * Copyright (c) 1997 Ben Harrison, and others
6 * This software may be copied and distributed for educational, research,
7 * and not for profit purposes provided that this copyright and statement
8 * are included in all such copies. Other copyrights may also apply.
9 */
11 #include "angband.h"
17 * Some "local" parameters, used to help write savefiles
20 static FILE *fff; /* Current save "file" */
22 static byte xor_byte; /* Simple encryption */
24 static u32b v_stamp = 0L; /* A simple "checksum" on the actual values */
25 static u32b x_stamp = 0L; /* A simple "checksum" on the encoded bytes */
30 * These functions place information into a savefile a byte at a time
33 static void sf_put(byte v)
35 /* Encode the value, write a character */
36 xor_byte ^= v;
37 (void)putc((int)xor_byte, fff);
39 /* Maintain the checksum info */
40 v_stamp += v;
41 x_stamp += xor_byte;
44 static void wr_byte(byte v)
46 sf_put(v);
49 static void wr_u16b(u16b v)
51 sf_put((byte)(v & 0xFF));
52 sf_put((byte)((v >> 8) & 0xFF));
55 static void wr_s16b(s16b v)
57 wr_u16b((u16b)v);
60 static void wr_u32b(u32b v)
62 sf_put((byte)(v & 0xFF));
63 sf_put((byte)((v >> 8) & 0xFF));
64 sf_put((byte)((v >> 16) & 0xFF));
65 sf_put((byte)((v >> 24) & 0xFF));
68 static void wr_s32b(s32b v)
70 wr_u32b((u32b)v);
73 static void wr_string(cptr str)
75 while (*str)
77 wr_byte(*str);
78 str++;
80 wr_byte(*str);
85 * These functions write info in larger logical records
90 * Write an "item" record
92 static void wr_item(const object_type *o_ptr)
94 wr_s16b(o_ptr->k_idx);
96 /* Location */
97 wr_byte(o_ptr->iy);
98 wr_byte(o_ptr->ix);
100 wr_byte(o_ptr->tval);
101 wr_byte(o_ptr->sval);
102 wr_s16b(o_ptr->pval);
104 wr_byte(o_ptr->pseudo);
106 wr_byte(o_ptr->number);
107 wr_s16b(o_ptr->weight);
109 wr_byte(o_ptr->name1);
110 wr_byte(o_ptr->name2);
112 wr_s16b(o_ptr->timeout);
114 wr_s16b(o_ptr->to_h);
115 wr_s16b(o_ptr->to_d);
116 wr_s16b(o_ptr->to_a);
117 wr_s16b(o_ptr->ac);
118 wr_byte(o_ptr->dd);
119 wr_byte(o_ptr->ds);
121 wr_byte(o_ptr->ident);
123 wr_byte(o_ptr->marked);
125 /* Old flags */
126 wr_u32b(0L);
127 wr_u32b(0L);
128 wr_u32b(0L);
130 /* Held by monster index */
131 wr_s16b(o_ptr->held_m_idx);
133 /* Extra information */
134 wr_byte(o_ptr->xtra1);
135 wr_byte(o_ptr->xtra2);
137 /* Save the inscription (if any) */
138 if (o_ptr->note)
140 wr_string(quark_str(o_ptr->note));
142 else
144 wr_string("");
150 * Write a "monster" record
152 static void wr_monster(const monster_type *m_ptr)
154 wr_s16b(m_ptr->r_idx);
155 wr_byte(m_ptr->fy);
156 wr_byte(m_ptr->fx);
157 wr_s16b(m_ptr->hp);
158 wr_s16b(m_ptr->maxhp);
159 wr_s16b(m_ptr->csleep);
160 wr_byte(m_ptr->mspeed);
161 wr_byte(m_ptr->energy);
162 wr_byte(m_ptr->stunned);
163 wr_byte(m_ptr->confused);
164 wr_byte(m_ptr->monfear);
165 wr_byte(0);
170 * Write a "lore" record
172 static void wr_lore(int r_idx)
174 int i;
176 monster_race *r_ptr = &r_info[r_idx];
177 monster_lore *l_ptr = &l_list[r_idx];
179 /* Count sights/deaths/kills */
180 wr_s16b(l_ptr->sights);
181 wr_s16b(l_ptr->deaths);
182 wr_s16b(l_ptr->pkills);
183 wr_s16b(l_ptr->tkills);
185 /* Count wakes and ignores */
186 wr_byte(l_ptr->wake);
187 wr_byte(l_ptr->ignore);
189 /* Extra stuff */
190 wr_byte(l_ptr->xtra1);
191 wr_byte(l_ptr->xtra2);
193 /* Count drops */
194 wr_byte(l_ptr->drop_gold);
195 wr_byte(l_ptr->drop_item);
197 /* Count spells */
198 wr_byte(l_ptr->cast_innate);
199 wr_byte(l_ptr->cast_spell);
201 /* Count blows of each type */
202 for (i = 0; i < MONSTER_BLOW_MAX; i++)
203 wr_byte(l_ptr->blows[i]);
205 /* Memorize flags */
206 wr_u32b(l_ptr->flags1);
207 wr_u32b(l_ptr->flags2);
208 wr_u32b(l_ptr->flags3);
209 wr_u32b(l_ptr->flags4);
210 wr_u32b(l_ptr->flags5);
211 wr_u32b(l_ptr->flags6);
214 /* Monster limit per level */
215 wr_byte(r_ptr->max_num);
217 /* Later (?) */
218 wr_byte(0);
219 wr_byte(0);
220 wr_byte(0);
225 * Write an "xtra" record
227 static void wr_xtra(int k_idx)
229 byte tmp8u = 0;
231 object_kind *k_ptr = &k_info[k_idx];
233 if (k_ptr->aware) tmp8u |= 0x01;
234 if (k_ptr->tried) tmp8u |= 0x02;
235 if (k_ptr->squelch) tmp8u |= 0x04;
236 if (k_ptr->everseen) tmp8u |= 0x08;
238 wr_byte(tmp8u);
243 * Write a "store" record
245 static void wr_store(const store_type *st_ptr)
247 int j;
249 /* XXX Old value (<= Angband 3.0.3) */
250 wr_u32b(0L);
252 /* XXX Old value (<= Angband 3.0.3) */
253 wr_s16b(0);
255 /* Save the current owner */
256 wr_byte(st_ptr->owner);
258 /* Save the stock size */
259 wr_byte(st_ptr->stock_num);
261 /* XXX Old values (<= Angband 3.0.3) */
262 wr_s16b(0);
263 wr_s16b(0);
265 /* Save the stock */
266 for (j = 0; j < st_ptr->stock_num; j++)
268 /* Save each item in stock */
269 wr_item(&st_ptr->stock[j]);
275 * Write RNG state
277 static errr wr_randomizer(void)
279 int i;
281 /* Zero */
282 wr_u16b(0);
284 /* Place */
285 wr_u16b(Rand_place);
287 /* State */
288 for (i = 0; i < RAND_DEG; i++)
290 wr_u32b(Rand_state[i]);
293 /* Success */
294 return (0);
299 * Write the "options"
301 static void wr_options(void)
303 int i, k;
305 u32b flag[8];
306 u32b mask[8];
307 u32b window_flag[ANGBAND_TERM_MAX];
308 u32b window_mask[ANGBAND_TERM_MAX];
311 /*** Oops ***/
313 /* Oops */
314 for (i = 0; i < 4; i++) wr_u32b(0L);
317 /*** Special Options ***/
319 /* Write "delay_factor" */
320 wr_byte(op_ptr->delay_factor);
322 /* Write "hitpoint_warn" */
323 wr_byte(op_ptr->hitpoint_warn);
325 wr_u16b(0); /* oops */
328 /*** Normal options ***/
330 /* Reset */
331 for (i = 0; i < 8; i++)
333 flag[i] = 0L;
334 mask[i] = 0L;
337 /* Analyze the options */
338 for (i = 0; i < OPT_MAX; i++)
340 int os = i / 32;
341 int ob = i % 32;
343 /* Process real entries */
344 if (option_text[i])
346 /* Set flag */
347 if (op_ptr->opt[i])
349 /* Set */
350 flag[os] |= (1L << ob);
353 /* Set mask */
354 mask[os] |= (1L << ob);
358 /* Dump the flags */
359 for (i = 0; i < 8; i++) wr_u32b(flag[i]);
361 /* Dump the masks */
362 for (i = 0; i < 8; i++) wr_u32b(mask[i]);
365 /*** Window options ***/
367 /* Reset */
368 for (i = 0; i < ANGBAND_TERM_MAX; i++)
370 /* Flags */
371 window_flag[i] = op_ptr->window_flag[i];
373 /* Mask */
374 window_mask[i] = 0L;
376 /* Build the mask */
377 for (k = 0; k < 32; k++)
379 /* Set mask */
380 if (window_flag_desc[k])
382 window_mask[i] |= (1L << k);
387 /* Dump the flags */
388 for (i = 0; i < ANGBAND_TERM_MAX; i++) wr_u32b(window_flag[i]);
390 /* Dump the masks */
391 for (i = 0; i < ANGBAND_TERM_MAX; i++) wr_u32b(window_mask[i]);
396 * Hack -- Write the "ghost" info
398 static void wr_ghost(void)
400 int i;
402 /* Name */
403 wr_string("Broken Ghost");
405 /* Hack -- stupid data */
406 for (i = 0; i < 60; i++) wr_byte(0);
411 * Write autoinscribe & squelch item-quality submenu to the savefile
413 static void wr_squelch(void)
415 int i;
417 /* Write number of squelch bytes */
418 wr_byte(SQUELCH_BYTES);
419 for (i = 0; i < SQUELCH_BYTES; i++)
420 wr_byte(squelch_level[i]);
422 /* Write ego-item squelch bits */
423 wr_u16b(z_info->e_max);
424 for (i = 0; i < z_info->e_max; i++)
426 byte flags = 0;
428 /* Figure out and write the everseen flag */
429 if (e_info[i].everseen) flags |= 0x02;
430 wr_byte(flags);
433 /* Write the current number of auto-inscriptions */
434 wr_u16b(inscriptions_count);
436 /* Write the autoinscriptions array */
437 for (i = 0; i < inscriptions_count; i++)
439 wr_s16b(inscriptions[i].kind_idx);
440 wr_string(quark_str(inscriptions[i].inscription_idx));
443 return;
448 * Write some "extra" info
450 static void wr_extra(void)
452 int i;
454 wr_string(op_ptr->full_name);
456 wr_string(p_ptr->died_from);
458 wr_string(p_ptr->history);
460 /* Race/Class/Gender/Spells */
461 wr_byte(p_ptr->prace);
462 wr_byte(p_ptr->pclass);
463 wr_byte(p_ptr->psex);
464 wr_byte(0); /* oops */
466 wr_byte(p_ptr->hitdie);
467 wr_byte(p_ptr->expfact);
469 wr_s16b(p_ptr->age);
470 wr_s16b(p_ptr->ht);
471 wr_s16b(p_ptr->wt);
473 /* Dump the stats (maximum and current) */
474 for (i = 0; i < A_MAX; ++i) wr_s16b(p_ptr->stat_max[i]);
475 for (i = 0; i < A_MAX; ++i) wr_s16b(p_ptr->stat_cur[i]);
477 /* Ignore the transient stats */
478 for (i = 0; i < 12; ++i) wr_s16b(0);
480 wr_u32b(p_ptr->au);
482 wr_u32b(p_ptr->max_exp);
483 wr_u32b(p_ptr->exp);
484 wr_u16b(p_ptr->exp_frac);
485 wr_s16b(p_ptr->lev);
487 wr_s16b(p_ptr->mhp);
488 wr_s16b(p_ptr->chp);
489 wr_u16b(p_ptr->chp_frac);
491 wr_s16b(p_ptr->msp);
492 wr_s16b(p_ptr->csp);
493 wr_u16b(p_ptr->csp_frac);
495 /* Max Player and Dungeon Levels */
496 wr_s16b(p_ptr->max_lev);
497 wr_s16b(p_ptr->max_depth);
499 /* More info */
500 wr_s16b(0); /* oops */
501 wr_s16b(0); /* oops */
502 wr_s16b(0); /* oops */
503 wr_s16b(0); /* oops */
504 wr_s16b(p_ptr->sc);
505 wr_s16b(0); /* oops */
507 wr_s16b(p_ptr->food);
508 wr_s16b(p_ptr->energy);
509 wr_s16b(p_ptr->word_recall);
510 wr_s16b(p_ptr->see_infra);
511 wr_byte(p_ptr->confusing);
512 wr_byte(p_ptr->searching);
514 /* Find the number of timed effects */
515 wr_byte(TMD_MAX);
517 /* Read all the effects, in a loop */
518 for (i = 0; i < TMD_MAX; i++)
519 wr_s16b(p_ptr->timed[i]);
521 /* Future use */
522 for (i = 0; i < 10; i++) wr_u32b(0L);
524 wr_squelch();
526 /* Random artifact version */
527 wr_u32b(RANDART_VERSION);
529 /* Random artifact seed */
530 wr_u32b(seed_randart);
533 /* Ignore some flags */
534 wr_u32b(0L); /* oops */
535 wr_u32b(0L); /* oops */
536 wr_u32b(0L); /* oops */
539 /* Write the "object seeds" */
540 wr_u32b(seed_flavor);
541 wr_u32b(seed_town);
544 /* Special stuff */
545 wr_u16b(p_ptr->panic_save);
546 wr_u16b(p_ptr->total_winner);
547 wr_u16b(p_ptr->noscore);
550 /* Write death */
551 wr_byte(p_ptr->is_dead);
553 /* Write feeling */
554 wr_byte(feeling);
556 /* Turn of last "feeling" */
557 wr_s32b(old_turn);
559 /* Current turn */
560 wr_s32b(turn);
565 * Dump the random artifacts
567 static void wr_randarts(void)
569 int i;
571 wr_u16b(z_info->a_max);
573 for (i = 0; i < z_info->a_max; i++)
575 artifact_type *a_ptr = &a_info[i];
577 wr_byte(a_ptr->tval);
578 wr_byte(a_ptr->sval);
579 wr_s16b(a_ptr->pval);
581 wr_s16b(a_ptr->to_h);
582 wr_s16b(a_ptr->to_d);
583 wr_s16b(a_ptr->to_a);
584 wr_s16b(a_ptr->ac);
586 wr_byte(a_ptr->dd);
587 wr_byte(a_ptr->ds);
589 wr_s16b(a_ptr->weight);
591 wr_s32b(a_ptr->cost);
593 wr_u32b(a_ptr->flags1);
594 wr_u32b(a_ptr->flags2);
595 wr_u32b(a_ptr->flags3);
597 wr_byte(a_ptr->level);
598 wr_byte(a_ptr->rarity);
600 wr_byte(a_ptr->activation);
601 wr_u16b(a_ptr->time);
602 wr_u16b(a_ptr->randtime);
608 * The cave grid flags that get saved in the savefile
610 #define IMPORTANT_FLAGS (CAVE_MARK | CAVE_GLOW | CAVE_ICKY | CAVE_ROOM)
614 * Write the current dungeon
616 static void wr_dungeon(void)
618 int i, y, x;
620 byte tmp8u;
622 byte count;
623 byte prev_char;
626 /*** Basic info ***/
628 /* Dungeon specific info follows */
629 wr_u16b(p_ptr->depth);
630 wr_u16b(0);
631 wr_u16b(p_ptr->py);
632 wr_u16b(p_ptr->px);
633 wr_u16b(DUNGEON_HGT);
634 wr_u16b(DUNGEON_WID);
635 wr_u16b(0);
636 wr_u16b(0);
639 /*** Simple "Run-Length-Encoding" of cave ***/
641 /* Note that this will induce two wasted bytes */
642 count = 0;
643 prev_char = 0;
645 /* Dump the cave */
646 for (y = 0; y < DUNGEON_HGT; y++)
648 for (x = 0; x < DUNGEON_WID; x++)
650 /* Extract the important cave_info flags */
651 tmp8u = (cave_info[y][x] & (IMPORTANT_FLAGS));
653 /* If the run is broken, or too full, flush it */
654 if ((tmp8u != prev_char) || (count == MAX_UCHAR))
656 wr_byte((byte)count);
657 wr_byte((byte)prev_char);
658 prev_char = tmp8u;
659 count = 1;
662 /* Continue the run */
663 else
665 count++;
670 /* Flush the data (if any) */
671 if (count)
673 wr_byte((byte)count);
674 wr_byte((byte)prev_char);
678 /*** Simple "Run-Length-Encoding" of cave ***/
680 /* Note that this will induce two wasted bytes */
681 count = 0;
682 prev_char = 0;
684 /* Dump the cave */
685 for (y = 0; y < DUNGEON_HGT; y++)
687 for (x = 0; x < DUNGEON_WID; x++)
689 /* Extract a byte */
690 tmp8u = cave_feat[y][x];
692 /* If the run is broken, or too full, flush it */
693 if ((tmp8u != prev_char) || (count == MAX_UCHAR))
695 wr_byte((byte)count);
696 wr_byte((byte)prev_char);
697 prev_char = tmp8u;
698 count = 1;
701 /* Continue the run */
702 else
704 count++;
709 /* Flush the data (if any) */
710 if (count)
712 wr_byte((byte)count);
713 wr_byte((byte)prev_char);
717 /*** Compact ***/
719 /* Compact the objects */
720 compact_objects(0);
722 /* Compact the monsters */
723 compact_monsters(0);
726 /*** Dump objects ***/
728 /* Total objects */
729 wr_u16b(o_max);
731 /* Dump the objects */
732 for (i = 1; i < o_max; i++)
734 object_type *o_ptr = &o_list[i];
736 /* Dump it */
737 wr_item(o_ptr);
741 /*** Dump the monsters ***/
743 /* Total monsters */
744 wr_u16b(mon_max);
746 /* Dump the monsters */
747 for (i = 1; i < mon_max; i++)
749 monster_type *m_ptr = &mon_list[i];
751 /* Dump it */
752 wr_monster(m_ptr);
759 * Actually write a save-file
761 static bool wr_savefile_new(void)
763 int i;
765 u32b now;
767 u16b tmp16u;
770 /* Guess at the current time */
771 now = time((time_t *)0);
774 /* Note the operating system */
775 sf_xtra = 0L;
777 /* Note when the file was saved */
778 sf_when = now;
780 /* Note the number of saves */
781 sf_saves++;
784 /*** Actually write the file ***/
786 /* Dump the file header */
787 xor_byte = 0;
788 wr_byte(VERSION_MAJOR);
789 xor_byte = 0;
790 wr_byte(VERSION_MINOR);
791 xor_byte = 0;
792 wr_byte(VERSION_PATCH);
793 xor_byte = 0;
794 wr_byte(VERSION_EXTRA);
797 /* Reset the checksum */
798 v_stamp = 0L;
799 x_stamp = 0L;
802 /* Operating system */
803 wr_u32b(sf_xtra);
806 /* Time file last saved */
807 wr_u32b(sf_when);
809 /* Number of past lives */
810 wr_u16b(sf_lives);
812 /* Number of times saved */
813 wr_u16b(sf_saves);
816 /* Space */
817 wr_u32b(0L);
818 wr_u32b(0L);
821 /* Write the RNG state */
822 wr_randomizer();
825 /* Write the boolean "options" */
826 wr_options();
829 /* Dump the number of "messages" */
830 tmp16u = message_num();
831 if (tmp16u > 80) tmp16u = 80;
832 wr_u16b(tmp16u);
834 /* Dump the messages (oldest first!) */
835 for (i = tmp16u - 1; i >= 0; i--)
837 wr_string(message_str((s16b)i));
838 wr_u16b(message_type((s16b)i));
842 /* Dump the monster lore */
843 tmp16u = z_info->r_max;
844 wr_u16b(tmp16u);
845 for (i = 0; i < tmp16u; i++) wr_lore(i);
848 /* Dump the object memory */
849 tmp16u = z_info->k_max;
850 wr_u16b(tmp16u);
851 for (i = 0; i < tmp16u; i++) wr_xtra(i);
854 /* Hack -- Dump the quests */
855 tmp16u = MAX_Q_IDX;
856 wr_u16b(tmp16u);
857 for (i = 0; i < tmp16u; i++)
859 wr_byte(q_list[i].level);
860 wr_byte(0);
861 wr_byte(0);
862 wr_byte(0);
865 /* Hack -- Dump the artifacts */
866 tmp16u = z_info->a_max;
867 wr_u16b(tmp16u);
868 for (i = 0; i < tmp16u; i++)
870 artifact_type *a_ptr = &a_info[i];
871 wr_byte(a_ptr->cur_num);
872 wr_byte(0);
873 wr_byte(0);
874 wr_byte(0);
878 /* Write the "extra" information */
879 wr_extra();
882 /* Dump the "player hp" entries */
883 tmp16u = PY_MAX_LEVEL;
884 wr_u16b(tmp16u);
885 for (i = 0; i < tmp16u; i++)
887 wr_s16b(p_ptr->player_hp[i]);
891 /* Write spell data */
892 wr_u16b(PY_MAX_SPELLS);
894 for (i = 0; i < PY_MAX_SPELLS; i++)
896 wr_byte(p_ptr->spell_flags[i]);
899 /* Dump the ordered spells */
900 for (i = 0; i < PY_MAX_SPELLS; i++)
902 wr_byte(p_ptr->spell_order[i]);
906 /* Write randart information */
907 if (adult_randarts)
909 wr_randarts();
913 /* Write the inventory */
914 for (i = 0; i < INVEN_TOTAL; i++)
916 object_type *o_ptr = &inventory[i];
918 /* Skip non-objects */
919 if (!o_ptr->k_idx) continue;
921 /* Dump index */
922 wr_u16b((u16b)i);
924 /* Dump object */
925 wr_item(o_ptr);
928 /* Add a sentinel */
929 wr_u16b(0xFFFF);
932 /* Note the stores */
933 tmp16u = MAX_STORES;
934 wr_u16b(tmp16u);
936 /* Dump the stores */
937 for (i = 0; i < tmp16u; i++) wr_store(&store[i]);
940 /* Player is not dead, write the dungeon */
941 if (!p_ptr->is_dead)
943 /* Dump the dungeon */
944 wr_dungeon();
946 /* Dump the ghost */
947 wr_ghost();
951 /* Write the "value check-sum" */
952 wr_u32b(v_stamp);
954 /* Write the "encoded checksum" */
955 wr_u32b(x_stamp);
958 /* Error in save */
959 if (ferror(fff) || (fflush(fff) == EOF)) return FALSE;
961 /* Successful save */
962 return TRUE;
967 * Medium level player saver
969 static bool save_player_aux(cptr name)
971 bool ok = FALSE;
973 int fd;
975 int mode = 0644;
978 /* No file yet */
979 fff = NULL;
982 /* File type is "SAVE" */
983 FILE_TYPE(FILE_TYPE_SAVE);
986 /* Grab permissions */
987 safe_setuid_grab();
989 /* Create the savefile */
990 fd = fd_make(name, mode);
992 /* Drop permissions */
993 safe_setuid_drop();
995 /* File is okay */
996 if (fd >= 0)
998 /* Close the "fd" */
999 fd_close(fd);
1001 /* Grab permissions */
1002 safe_setuid_grab();
1004 /* Open the savefile */
1005 fff = my_fopen(name, "wb");
1007 /* Drop permissions */
1008 safe_setuid_drop();
1010 /* Successful open */
1011 if (fff)
1013 /* Write the savefile */
1014 if (wr_savefile_new()) ok = TRUE;
1016 /* Attempt to close it */
1017 if (my_fclose(fff)) ok = FALSE;
1020 /* Grab permissions */
1021 safe_setuid_grab();
1023 /* Remove "broken" files */
1024 if (!ok) fd_kill(name);
1026 /* Drop permissions */
1027 safe_setuid_drop();
1031 /* Failure */
1032 if (!ok) return (FALSE);
1034 /* Successful save */
1035 character_saved = TRUE;
1037 /* Success */
1038 return (TRUE);
1044 * Attempt to save the player in a savefile
1046 bool save_player(void)
1048 int result = FALSE;
1050 char safe[1024];
1053 /* New savefile */
1054 my_strcpy(safe, savefile, sizeof(safe));
1055 my_strcat(safe, ".new", sizeof(safe));
1057 /* Grab permissions */
1058 safe_setuid_grab();
1060 /* Remove it */
1061 fd_kill(safe);
1063 /* Drop permissions */
1064 safe_setuid_drop();
1066 /* Attempt to save the player */
1067 if (save_player_aux(safe))
1069 char temp[1024];
1071 /* Old savefile */
1072 my_strcpy(temp, savefile, sizeof(temp));
1073 my_strcat(temp, ".old", sizeof(temp));
1075 /* Grab permissions */
1076 safe_setuid_grab();
1078 /* Remove it */
1079 fd_kill(temp);
1081 /* Preserve old savefile */
1082 fd_move(savefile, temp);
1084 /* Activate new savefile */
1085 fd_move(safe, savefile);
1087 /* Remove preserved savefile */
1088 fd_kill(temp);
1090 /* Drop permissions */
1091 safe_setuid_drop();
1093 /* Success */
1094 result = TRUE;
1098 /* Return the result */
1099 return (result);