Anope IRC Services  Version 1.8
datafiles.c
Go to the documentation of this file.
1 /* Database file handling routines.
2  *
3  * (C) 2003-2014 Anope Team
4  * Contact us at team@anope.org
5  *
6  * Please read COPYING and README for further details.
7  *
8  * Based on the original code of Epona by Lara.
9  * Based on the original code of Services by Andy Church.
10  *
11  *
12  */
13 
14 #include "services.h"
15 #include "datafiles.h"
16 #include <fcntl.h>
17 
18 static int curday = 0;
19 static time_t lastwarn = 0;
20 
21 /*************************************************************************/
22 
31 {
32  FILE *fp = f->fp;
33  int version =
34  fgetc(fp) << 24 | fgetc(fp) << 16 | fgetc(fp) << 8 | fgetc(fp);
35  if (ferror(fp)) {
36 #ifndef NOT_MAIN
37  log_perror("Error reading version number on %s", f->filename);
38 #endif
39  return 0;
40  } else if (feof(fp)) {
41 #ifndef NOT_MAIN
42  alog("Error reading version number on %s: End of file detected",
43  f->filename);
44 #endif
45  return 0;
46  } else if (version < 1) {
47 #ifndef NOT_MAIN
48  alog("Invalid version number (%d) on %s", version, f->filename);
49 #endif
50  return 0;
51  }
52  return version;
53 }
54 
55 /*************************************************************************/
56 
63 {
64  FILE *fp = f->fp;
65  if (fputc(version >> 24 & 0xFF, fp) < 0 ||
66  fputc(version >> 16 & 0xFF, fp) < 0 ||
67  fputc(version >> 8 & 0xFF, fp) < 0 ||
68  fputc(version & 0xFF, fp) < 0) {
69 #ifndef NOT_MAIN
70  log_perror("Error writing version number on %s", f->filename);
71 #endif
72  return 0;
73  }
74  return 1;
75 }
76 
77 /*************************************************************************/
78 
85 static dbFILE *open_db_read(const char *service, const char *filename)
86 {
87  dbFILE *f;
88  FILE *fp;
89 
90  f = scalloc(sizeof(*f), 1);
91  if (!f) {
92 #ifndef NOT_MAIN
93  log_perror("Can't read %s database %s", service, filename);
94  if (time(NULL) - lastwarn > WarningTimeout) {
95  anope_cmd_global(NULL,
96  "Write error on %s: Memory allocation failed",
97  filename);
98  lastwarn = time(NULL);
99  }
100 #endif
101  return NULL;
102  }
103  strscpy(f->filename, filename, sizeof(f->filename));
104  f->mode = 'r';
105  fp = fopen(f->filename, "rb");
106  if (!fp) {
107  int errno_save = errno;
108 #ifndef NOT_MAIN
109  if (errno != ENOENT)
110  log_perror("Can not read %s database %s", service,
111  f->filename);
112  if (time(NULL) - lastwarn > WarningTimeout) {
113  anope_cmd_global(NULL, "Write error on %s: %s", f->filename,
114  strerror(errno));
115  lastwarn = time(NULL);
116  }
117 #endif
118  free(f);
119  errno = errno_save;
120  return NULL;
121  }
122  f->fp = fp;
123  f->backupfp = NULL;
124  return f;
125 }
126 
127 /*************************************************************************/
128 
136 static dbFILE *open_db_write(const char *service, const char *filename,
137  uint32 version)
138 {
139  dbFILE *f;
140  int fd;
141 #ifdef _WIN32
142  char buffer[_MAX_PATH];
143  char win32filename[MAXPATHLEN];
144 
145  /* Get the current working directory: */
146  if (_getcwd(buffer, _MAX_PATH) == NULL) {
147  alog("Warning: Unable to set Current working directory");
148  }
149 #endif
150 
151  f = scalloc(sizeof(*f), 1);
152  if (!f) {
153 #ifndef NOT_MAIN
154  log_perror("Can not read %s database %s", service, filename);
155 #else
156  alog("Can not read %s database %s", service, filename);
157 #endif
158  return NULL;
159  }
160  strscpy(f->filename, filename, sizeof(f->filename));
161 #ifndef _WIN32
162  filename = f->filename;
163 #else
164  snprintf(win32filename, sizeof(win32filename), "%s\\%s", buffer,
165  f->filename);
166  filename = win32filename;
167 #endif
168  f->mode = 'w';
169 
170  *f->backupname = 0;
171  snprintf(f->backupname, sizeof(f->backupname), "%s.save", filename);
172  if (!*f->backupname || strcmp(f->backupname, filename) == 0) {
173  int errno_save = errno;
174 #ifndef NOT_MAIN
175  alog("Opening %s database %s for write: Filename too long",
176  service, filename);
177 #endif
178  free(f);
179  errno = errno_save;
180  return NULL;
181  }
182 #ifndef _WIN32
183  unlink(filename);
184 #else
185  DeleteFile(filename);
186 #endif
187  f->backupfp = fopen(filename, "rb");
188 #ifdef _WIN32
189  if (!MoveFileExA(filename, f->backupname, MOVEFILE_COPY_ALLOWED)
190  && GetLastError() != ENOENT) {
191  int errno_save = GetLastError();
192 #else
193  if (rename(filename, f->backupname) < 0 && errno != ENOENT) {
194  int errno_save = errno;
195 #endif
196 #ifndef NOT_MAIN
197  static int walloped = 0;
198  if (!walloped) {
199  walloped++;
200  anope_cmd_global(NULL, "Can not back up %s database %s",
201  service, filename);
202  }
203 #ifdef _WIN32
204  if (debug) {
205  if (errno == ENOENT) {
206  alog("debug: Error %d (ENOENT) : the file or directory does not exist", errno, filename);
207  } else if (errno == EACCES) {
208  alog("debug: Error %d (EACCES) : error while attempting to access file", errno);
209  } else {
210  alog("debug: Error %d", errno);
211  }
212  }
213 #else
214  if (debug) {
215  alog("debug: Error %d", errno);
216  }
217 #endif
218  errno = errno_save;
219  log_perror("Can not back up %s database %s", service, filename);
220  if (!NoBackupOkay) {
221 #endif
222  if (f->backupfp)
223  fclose(f->backupfp);
224  free(f);
225  errno = errno_save;
226  return NULL;
227 #ifndef NOT_MAIN
228  }
229 #endif
230  *f->backupname = 0;
231  }
232 #ifndef _WIN32
233  unlink(filename);
234 #else
235  DeleteFile(filename);
236 #endif
237  /* Use open() to avoid people sneaking a new file in under us */
238 #ifndef _WIN32
239  fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0666);
240 #else
241  fd = open(filename, O_WRONLY | O_CREAT | O_EXCL | _O_BINARY, 0666);
242 #endif
243  f->fp = fdopen(fd, "wb"); /* will fail and return NULL if fd < 0 */
244  if (!f->fp || !write_file_version(f, version)) {
245  int errno_save = errno;
246 #ifndef NOT_MAIN
247  static int walloped = 0;
248  if (!walloped) {
249  walloped++;
250  anope_cmd_global(NULL, "Can't write to %s database %s",
251  service, filename);
252  }
253  errno = errno_save;
254  log_perror("Can't write to %s database %s", service, filename);
255 #endif
256  if (f->fp) {
257  fclose(f->fp);
258 #ifndef _WIN32
259  unlink(filename);
260 #else
261  DeleteFile(filename);
262 #endif
263  }
264  if (*f->backupname && rename(f->backupname, filename) < 0)
265 #ifndef NOT_MAIN
266  log_perror("Cannot restore backup copy of %s", filename);
267 #else
268  ;
269 #endif
270  /* Then the Lord said unto Moses, thou shalt free what thou hast malloced
271  * -- codemastr */
272  free(f);
273  errno = errno_save;
274  return NULL;
275  }
276  return f;
277 }
278 
279 /*************************************************************************/
280 
295 dbFILE *open_db(const char *service, const char *filename,
296  const char *mode, uint32 version)
297 {
298  if (*mode == 'r') {
299  return open_db_read(service, filename);
300  } else if (*mode == 'w') {
301  return open_db_write(service, filename, version);
302  } else {
303  errno = EINVAL;
304  return NULL;
305  }
306 }
307 
308 /*************************************************************************/
309 
319 {
320  int errno_save = errno;
321 
322  if (f->mode == 'w') {
323  int ok = 0; /* Did we manage to restore the old file? */
324  errno = errno_save = 0;
325  if (*f->backupname && strcmp(f->backupname, f->filename) != 0) {
326  if (rename(f->backupname, f->filename) == 0)
327  ok = 1;
328  }
329  if (!ok && f->backupfp) {
330  char buf[1024];
331  int i;
332  ok = 1;
333  if (fseek(f->fp, 0, SEEK_SET) < 0)
334  ok = 0;
335  while (ok && (i = fread(buf, 1, sizeof(buf), f->backupfp)) > 0) {
336  if (fwrite(buf, 1, i, f->fp) != i)
337  ok = 0;
338  }
339  if (ok) {
340  fflush(f->fp);
341  ftruncate(fileno(f->fp), ftell(f->fp));
342  }
343  }
344 #ifndef NOT_MAIN
345  if (!ok && errno > 0)
346  log_perror("Unable to restore backup of %s", f->filename);
347 #endif
348  errno_save = errno;
349  if (f->backupfp)
350  fclose(f->backupfp);
351  if (*f->backupname)
352 #ifndef _WIN32
353  unlink(f->backupname);
354 #else
355  DeleteFile(f->backupname);
356 #endif
357  }
358  fclose(f->fp);
359  if (!errno_save)
360  errno_save = errno;
361  free(f);
362  errno = errno_save;
363 }
364 
365 /*************************************************************************/
366 
373 void close_db(dbFILE * f)
374 {
375  if (f->mode == 'w' && *f->backupname
376  && strcmp(f->backupname, f->filename) != 0) {
377  if (f->backupfp)
378  fclose(f->backupfp);
379 #ifndef _WIN32
380  unlink(f->backupname);
381 #else
382  DeleteFile(f->backupname);
383 #endif
384  }
385  fclose(f->fp);
386  free(f);
387 }
388 
389 /*************************************************************************/
390 
405 int read_int16(uint16 * ret, dbFILE * f)
406 {
407  int c1, c2;
408 
409  c1 = fgetc(f->fp);
410  c2 = fgetc(f->fp);
411  if (c1 == EOF || c2 == EOF)
412  return -1;
413  *ret = c1 << 8 | c2;
414  return 0;
415 }
416 
417 /*************************************************************************/
418 
426 int write_int16(uint16 val, dbFILE * f)
427 {
428  if (fputc((val >> 8) & 0xFF, f->fp) == EOF
429  || fputc(val & 0xFF, f->fp) == EOF) {
430  return -1;
431  }
432  return 0;
433 }
434 
435 /*************************************************************************/
436 
444 int read_int32(uint32 * ret, dbFILE * f)
445 {
446  int c1, c2, c3, c4;
447 
448  c1 = fgetc(f->fp);
449  c2 = fgetc(f->fp);
450  c3 = fgetc(f->fp);
451  c4 = fgetc(f->fp);
452  if (c1 == EOF || c2 == EOF || c3 == EOF || c4 == EOF)
453  return -1;
454  *ret = c1 << 24 | c2 << 16 | c3 << 8 | c4;
455  return 0;
456 }
457 
458 /*************************************************************************/
459 
467 int write_int32(uint32 val, dbFILE * f)
468 {
469  if (fputc((val >> 24) & 0xFF, f->fp) == EOF)
470  return -1;
471  if (fputc((val >> 16) & 0xFF, f->fp) == EOF)
472  return -1;
473  if (fputc((val >> 8) & 0xFF, f->fp) == EOF)
474  return -1;
475  if (fputc((val) & 0xFF, f->fp) == EOF)
476  return -1;
477  return 0;
478 }
479 
480 /*************************************************************************/
481 
489 int read_ptr(void **ret, dbFILE * f)
490 {
491  int c;
492 
493  c = fgetc(f->fp);
494  if (c == EOF)
495  return -1;
496  *ret = (c ? (void *) 1 : (void *) 0);
497  return 0;
498 }
499 
500 /*************************************************************************/
501 
509 int write_ptr(const void *ptr, dbFILE * f)
510 {
511  if (fputc(ptr ? 1 : 0, f->fp) == EOF)
512  return -1;
513  return 0;
514 }
515 
516 /*************************************************************************/
517 
525 int read_string(char **ret, dbFILE * f)
526 {
527  char *s;
528  uint16 len;
529 
530  if (read_int16(&len, f) < 0)
531  return -1;
532  if (len == 0) {
533  *ret = NULL;
534  return 0;
535  }
536  s = scalloc(len, 1);
537  if (len != fread(s, 1, len, f->fp)) {
538  free(s);
539  return -1;
540  }
541  *ret = s;
542  return 0;
543 }
544 
545 /*************************************************************************/
546 
554 int write_string(const char *s, dbFILE * f)
555 {
556  uint32 len;
557 
558  if (!s)
559  return write_int16(0, f);
560  len = strlen(s);
561  if (len > 65534)
562  len = 65534;
563  if (write_int16((uint16) (len + 1), f) < 0)
564  return -1;
565  if (len > 0 && fwrite(s, 1, len, f->fp) != len)
566  return -1;
567  if (fputc(0, f->fp) == EOF)
568  return -1;
569  return 0;
570 }
571 
572 /*************************************************************************/
573 
581 static void rename_database(char *name, char *ext)
582 {
583 
584  char destpath[PATH_MAX];
585 
586  snprintf(destpath, sizeof(destpath), "backups/%s.%s", name, ext);
587  if (rename(name, destpath) != 0) {
588  alog("Backup of %s failed.", name);
589  anope_cmd_global(s_OperServ, "WARNING! Backup of %s failed.",
590  name);
591  }
592 }
593 
594 /*************************************************************************/
595 
601 static void remove_backups(void)
602 {
603 
604  char ext[9];
605  char path[PATH_MAX];
606 
607  time_t t;
608  struct tm tm;
609 
610  time(&t);
611  t -= (60 * 60 * 24 * KeepBackups);
612  tm = *localtime(&t);
613  strftime(ext, sizeof(ext), "%Y%m%d", &tm);
614 
615  snprintf(path, sizeof(path), "backups/%s.%s", NickDBName, ext);
616 #ifndef _WIN32
617  unlink(path);
618 #else
619  DeleteFile(path);
620 #endif
621  snprintf(path, sizeof(path), "backups/%s.%s", ChanDBName, ext);
622 #ifndef _WIN32
623  unlink(path);
624 #else
625  DeleteFile(path);
626 #endif
627  snprintf(path, sizeof(path), "backups/%s.%s", OperDBName, ext);
628 #ifndef _WIN32
629  unlink(path);
630 #else
631  DeleteFile(path);
632 #endif
633  snprintf(path, sizeof(path), "backups/%s.%s", NewsDBName, ext);
634 #ifndef _WIN32
635  unlink(path);
636 #else
637  DeleteFile(path);
638 #endif
639  snprintf(path, sizeof(path), "backups/%s.%s", ExceptionDBName, ext);
640 #ifndef _WIN32
641  unlink(path);
642 #else
643  DeleteFile(path);
644 #endif
645 
646  if (s_BotServ) {
647  snprintf(path, sizeof(path), "backups/%s.%s", BotDBName, ext);
648 #ifndef _WIN32
649  unlink(path);
650 #else
651  DeleteFile(path);
652 #endif
653  }
654  if (s_HostServ) {
655  snprintf(path, sizeof(path), "backups/%s.%s", HostDBName, ext);
656 #ifndef _WIN32
657  unlink(path);
658 #else
659  DeleteFile(path);
660 #endif
661  }
662  if (NSEmailReg) {
663  snprintf(path, sizeof(path), "backups/%s.%s", PreNickDBName, ext);
664 #ifndef _WIN32
665  unlink(path);
666 #else
667  DeleteFile(path);
668 #endif
669  }
670 }
671 
672 /*************************************************************************/
673 
680 {
681 
682  time_t t;
683  struct tm tm;
684 
685  if (!KeepBackups) {
686  return;
687  }
688 
689  time(&t);
690  tm = *localtime(&t);
691 
692  if (!curday) {
693  curday = tm.tm_yday;
694  return;
695  }
696 
697  if (curday != tm.tm_yday) {
698 
699  char ext[9];
700 
702  alog("Backing up databases");
703 
704  remove_backups();
705 
706  curday = tm.tm_yday;
707  strftime(ext, sizeof(ext), "%Y%m%d", &tm);
708 
709  if (!skeleton) {
711  if (s_BotServ) {
713  }
715  if (s_HostServ) {
717  }
718  if (NSEmailReg) {
720  }
721  }
722 
727  }
728 }
729 
730 /*************************************************************************/
731 
732 void ModuleDatabaseBackup(char *dbname)
733 {
734  char ext[9];
735  time_t t;
736  struct tm tm;
737 
738  if (!KeepBackups) {
739  return;
740  }
741 
742  time(&t);
743  tm = *localtime(&t);
744 
745  if (debug)
746  alog("Module Database Backing up %s", dbname);
747  ModuleRemoveBackups(dbname);
748  curday = tm.tm_yday;
749  strftime(ext, sizeof(ext), "%Y%m%d", &tm);
750  rename_database(dbname, ext);
751 }
752 
753 /*************************************************************************/
754 
755 void ModuleRemoveBackups(char *dbname)
756 {
757  char ext[9];
758  char path[PATH_MAX];
759 
760  time_t t;
761  struct tm tm;
762 
763  time(&t);
764  t -= (60 * 60 * 24 * KeepBackups);
765  tm = *localtime(&t);
766  strftime(ext, sizeof(ext), "%Y%m%d", &tm);
767 
768  snprintf(path, sizeof(path), "backups/%s.%s", dbname, ext);
769 #ifndef _WIN32
770  unlink(path);
771 #else
772  DeleteFile(path);
773 #endif
774 }
775 
776 /*************************************************************************/
E int KeepBackups
Definition: extern.h:350
int read_int32(uint32 *ret, dbFILE *f)
Definition: datafiles.c:444
E char * ExceptionDBName
Definition: extern.h:509
char filename[MAXPATHLEN]
Definition: datafiles.h:29
int get_file_version(dbFILE *f)
Definition: datafiles.c:30
E int WarningTimeout
Definition: extern.h:347
E int snprintf(char *buf, size_t size, const char *fmt,...)
Definition: compat.c:37
#define EVENT_STOP
Definition: events.h:15
void ModuleRemoveBackups(char *dbname)
Definition: datafiles.c:755
E char * s_BotServ
Definition: extern.h:287
E int NSEmailReg
Definition: extern.h:396
static int curday
Definition: datafiles.c:18
E char * PreNickDBName
Definition: extern.h:333
E void send_event(const char *name, int argc,...)
Definition: events.c:37
void ModuleDatabaseBackup(char *dbname)
Definition: datafiles.c:732
E char * OperDBName
Definition: extern.h:336
E char * NickDBName
Definition: extern.h:332
static dbFILE * open_db_read(const char *service, const char *filename)
Definition: datafiles.c:85
E char * HostDBName
Definition: extern.h:301
static void rename_database(char *name, char *ext)
Definition: datafiles.c:581
E char * strscpy(char *d, const char *s, size_t len)
Definition: db-merger.c:1886
E char * NewsDBName
Definition: extern.h:338
int write_int16(uint16 val, dbFILE *f)
Definition: datafiles.c:426
static void remove_backups(void)
Definition: datafiles.c:601
int write_file_version(dbFILE *f, uint32 version)
Definition: datafiles.c:62
E int NoBackupOkay
Definition: extern.h:340
void close_db(dbFILE *f)
Definition: datafiles.c:373
E void * scalloc(long elsize, long els)
Definition: memory.c:55
int read_ptr(void **ret, dbFILE *f)
Definition: datafiles.c:489
char backupname[MAXPATHLEN]
Definition: datafiles.h:30
E char * s_OperServ
Definition: extern.h:289
int write_int32(uint32 val, dbFILE *f)
Definition: datafiles.c:467
FILE * fp
Definition: datafiles.h:26
E char * strerror(int errnum)
Definition: compat.c:123
void backup_databases(void)
Definition: datafiles.c:679
Command * c
Definition: ns_recover.c:17
int write_ptr(const void *ptr, dbFILE *f)
Definition: datafiles.c:509
u_int32_t uint32
Definition: db-merger.c:123
E void alog(const char *fmt,...) FORMAT(printf
int write_string(const char *s, dbFILE *f)
Definition: datafiles.c:554
#define EVENT_START
Definition: events.h:14
E int debug
Definition: extern.h:775
int mode
Definition: datafiles.h:25
static time_t lastwarn
Definition: datafiles.c:19
void restore_db(dbFILE *f)
Definition: datafiles.c:318
E char * s_HostServ
Definition: extern.h:303
E int skeleton
Definition: extern.h:778
E char * ChanDBName
Definition: extern.h:334
FILE * backupfp
Definition: datafiles.h:27
int read_string(char **ret, dbFILE *f)
Definition: datafiles.c:525
int read_int16(uint16 *ret, dbFILE *f)
Definition: datafiles.c:405
dbFILE * open_db(const char *service, const char *filename, const char *mode, uint32 version)
Definition: datafiles.c:295
char version[1024]
Definition: version.sh.c:24
#define EVENT_DB_BACKUP
Definition: events.h:18
static dbFILE * open_db_write(const char *service, const char *filename, uint32 version)
Definition: datafiles.c:136
E void E void log_perror(const char *fmt,...) FORMAT(printf
E char * BotDBName
Definition: extern.h:335
E void anope_cmd_global(char *source, const char *fmt,...)
Definition: ircd.c:506
u_int16_t uint16
Definition: db-merger.c:121