00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include "services.h"
00015 #include "datafiles.h"
00016 #include <fcntl.h>
00017
00018 static int curday = 0;
00019 static time_t lastwarn = 0;
00020
00021
00022
00030 int get_file_version(dbFILE * f)
00031 {
00032 FILE *fp = f->fp;
00033 int version =
00034 fgetc(fp) << 24 | fgetc(fp) << 16 | fgetc(fp) << 8 | fgetc(fp);
00035 if (ferror(fp)) {
00036 #ifndef NOT_MAIN
00037 log_perror("Error reading version number on %s", f->filename);
00038 #endif
00039 return 0;
00040 } else if (feof(fp)) {
00041 #ifndef NOT_MAIN
00042 alog("Error reading version number on %s: End of file detected",
00043 f->filename);
00044 #endif
00045 return 0;
00046 } else if (version < 1) {
00047 #ifndef NOT_MAIN
00048 alog("Invalid version number (%d) on %s", version, f->filename);
00049 #endif
00050 return 0;
00051 }
00052 return version;
00053 }
00054
00055
00056
00062 int write_file_version(dbFILE * f, uint32 version)
00063 {
00064 FILE *fp = f->fp;
00065 if (fputc(version >> 24 & 0xFF, fp) < 0 ||
00066 fputc(version >> 16 & 0xFF, fp) < 0 ||
00067 fputc(version >> 8 & 0xFF, fp) < 0 ||
00068 fputc(version & 0xFF, fp) < 0) {
00069 #ifndef NOT_MAIN
00070 log_perror("Error writing version number on %s", f->filename);
00071 #endif
00072 return 0;
00073 }
00074 return 1;
00075 }
00076
00077
00078
00085 static dbFILE *open_db_read(const char *service, const char *filename)
00086 {
00087 dbFILE *f;
00088 FILE *fp;
00089
00090 f = scalloc(sizeof(*f), 1);
00091 if (!f) {
00092 #ifndef NOT_MAIN
00093 log_perror("Can't read %s database %s", service, filename);
00094 if (time(NULL) - lastwarn > WarningTimeout) {
00095 anope_cmd_global(NULL,
00096 "Write error on %s: Memory allocation failed",
00097 filename);
00098 lastwarn = time(NULL);
00099 }
00100 #endif
00101 return NULL;
00102 }
00103 strscpy(f->filename, filename, sizeof(f->filename));
00104 f->mode = 'r';
00105 fp = fopen(f->filename, "rb");
00106 if (!fp) {
00107 int errno_save = errno;
00108 #ifndef NOT_MAIN
00109 if (errno != ENOENT)
00110 log_perror("Can not read %s database %s", service,
00111 f->filename);
00112 if (time(NULL) - lastwarn > WarningTimeout) {
00113 anope_cmd_global(NULL, "Write error on %s: %s", f->filename,
00114 strerror(errno));
00115 lastwarn = time(NULL);
00116 }
00117 #endif
00118 free(f);
00119 errno = errno_save;
00120 return NULL;
00121 }
00122 f->fp = fp;
00123 f->backupfp = NULL;
00124 return f;
00125 }
00126
00127
00128
00136 static dbFILE *open_db_write(const char *service, const char *filename,
00137 uint32 version)
00138 {
00139 dbFILE *f;
00140 int fd;
00141 #ifdef _WIN32
00142 char buffer[_MAX_PATH];
00143 char win32filename[MAXPATHLEN];
00144
00145
00146 if (_getcwd(buffer, _MAX_PATH) == NULL) {
00147 alog("Warning: Unable to set Current working directory");
00148 }
00149 #endif
00150
00151 f = scalloc(sizeof(*f), 1);
00152 if (!f) {
00153 #ifndef NOT_MAIN
00154 log_perror("Can not read %s database %s", service, filename);
00155 #else
00156 alog("Can not read %s database %s", service, filename);
00157 #endif
00158 return NULL;
00159 }
00160 strscpy(f->filename, filename, sizeof(f->filename));
00161 #ifndef _WIN32
00162 filename = f->filename;
00163 #else
00164 snprintf(win32filename, sizeof(win32filename), "%s\\%s", buffer,
00165 f->filename);
00166 filename = win32filename;
00167 #endif
00168 f->mode = 'w';
00169
00170 *f->backupname = 0;
00171 snprintf(f->backupname, sizeof(f->backupname), "%s.save", filename);
00172 if (!*f->backupname || strcmp(f->backupname, filename) == 0) {
00173 int errno_save = errno;
00174 #ifndef NOT_MAIN
00175 alog("Opening %s database %s for write: Filename too long",
00176 service, filename);
00177 #endif
00178 free(f);
00179 errno = errno_save;
00180 return NULL;
00181 }
00182 #ifndef _WIN32
00183 unlink(filename);
00184 #else
00185 DeleteFile(filename);
00186 #endif
00187 f->backupfp = fopen(filename, "rb");
00188 #ifdef _WIN32
00189 if (!MoveFileExA(filename, f->backupname, MOVEFILE_COPY_ALLOWED)
00190 && GetLastError() != ENOENT) {
00191 int errno_save = GetLastError();
00192 #else
00193 if (rename(filename, f->backupname) < 0 && errno != ENOENT) {
00194 int errno_save = errno;
00195 #endif
00196 #ifndef NOT_MAIN
00197 static int walloped = 0;
00198 if (!walloped) {
00199 walloped++;
00200 anope_cmd_global(NULL, "Can not back up %s database %s",
00201 service, filename);
00202 }
00203 #ifdef _WIN32
00204 if (debug) {
00205 if (errno == ENOENT) {
00206 alog("debug: Error %d (ENOENT) : the file or directory does not exist", errno, filename);
00207 } else if (errno == EACCES) {
00208 alog("debug: Error %d (EACCES) : error while attempting to access file", errno);
00209 } else {
00210 alog("debug: Error %d", errno);
00211 }
00212 }
00213 #else
00214 if (debug) {
00215 alog("debug: Error %d", errno);
00216 }
00217 #endif
00218 errno = errno_save;
00219 log_perror("Can not back up %s database %s", service, filename);
00220 if (!NoBackupOkay) {
00221 #endif
00222 if (f->backupfp)
00223 fclose(f->backupfp);
00224 free(f);
00225 errno = errno_save;
00226 return NULL;
00227 #ifndef NOT_MAIN
00228 }
00229 #endif
00230 *f->backupname = 0;
00231 }
00232 #ifndef _WIN32
00233 unlink(filename);
00234 #else
00235 DeleteFile(filename);
00236 #endif
00237
00238 #ifndef _WIN32
00239 fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0666);
00240 #else
00241 fd = open(filename, O_WRONLY | O_CREAT | O_EXCL | _O_BINARY, 0666);
00242 #endif
00243 f->fp = fdopen(fd, "wb");
00244 if (!f->fp || !write_file_version(f, version)) {
00245 int errno_save = errno;
00246 #ifndef NOT_MAIN
00247 static int walloped = 0;
00248 if (!walloped) {
00249 walloped++;
00250 anope_cmd_global(NULL, "Can't write to %s database %s",
00251 service, filename);
00252 }
00253 errno = errno_save;
00254 log_perror("Can't write to %s database %s", service, filename);
00255 #endif
00256 if (f->fp) {
00257 fclose(f->fp);
00258 #ifndef _WIN32
00259 unlink(filename);
00260 #else
00261 DeleteFile(filename);
00262 #endif
00263 }
00264 if (*f->backupname && rename(f->backupname, filename) < 0)
00265 #ifndef NOT_MAIN
00266 log_perror("Cannot restore backup copy of %s", filename);
00267 #else
00268 ;
00269 #endif
00270
00271
00272 free(f);
00273 errno = errno_save;
00274 return NULL;
00275 }
00276 return f;
00277 }
00278
00279
00280
00295 dbFILE *open_db(const char *service, const char *filename,
00296 const char *mode, uint32 version)
00297 {
00298 if (*mode == 'r') {
00299 return open_db_read(service, filename);
00300 } else if (*mode == 'w') {
00301 return open_db_write(service, filename, version);
00302 } else {
00303 errno = EINVAL;
00304 return NULL;
00305 }
00306 }
00307
00308
00309
00318 void restore_db(dbFILE * f)
00319 {
00320 int errno_save = errno;
00321
00322 if (f->mode == 'w') {
00323 int ok = 0;
00324 errno = errno_save = 0;
00325 if (*f->backupname && strcmp(f->backupname, f->filename) != 0) {
00326 if (rename(f->backupname, f->filename) == 0)
00327 ok = 1;
00328 }
00329 if (!ok && f->backupfp) {
00330 char buf[1024];
00331 int i;
00332 ok = 1;
00333 if (fseek(f->fp, 0, SEEK_SET) < 0)
00334 ok = 0;
00335 while (ok && (i = fread(buf, 1, sizeof(buf), f->backupfp)) > 0) {
00336 if (fwrite(buf, 1, i, f->fp) != i)
00337 ok = 0;
00338 }
00339 if (ok) {
00340 fflush(f->fp);
00341 ftruncate(fileno(f->fp), ftell(f->fp));
00342 }
00343 }
00344 #ifndef NOT_MAIN
00345 if (!ok && errno > 0)
00346 log_perror("Unable to restore backup of %s", f->filename);
00347 #endif
00348 errno_save = errno;
00349 if (f->backupfp)
00350 fclose(f->backupfp);
00351 if (*f->backupname)
00352 #ifndef _WIN32
00353 unlink(f->backupname);
00354 #else
00355 DeleteFile(f->backupname);
00356 #endif
00357 }
00358 fclose(f->fp);
00359 if (!errno_save)
00360 errno_save = errno;
00361 free(f);
00362 errno = errno_save;
00363 }
00364
00365
00366
00373 void close_db(dbFILE * f)
00374 {
00375 if (f->mode == 'w' && *f->backupname
00376 && strcmp(f->backupname, f->filename) != 0) {
00377 if (f->backupfp)
00378 fclose(f->backupfp);
00379 #ifndef _WIN32
00380 unlink(f->backupname);
00381 #else
00382 DeleteFile(f->backupname);
00383 #endif
00384 }
00385 fclose(f->fp);
00386 free(f);
00387 }
00388
00389
00390
00405 int read_int16(uint16 * ret, dbFILE * f)
00406 {
00407 int c1, c2;
00408
00409 c1 = fgetc(f->fp);
00410 c2 = fgetc(f->fp);
00411 if (c1 == EOF || c2 == EOF)
00412 return -1;
00413 *ret = c1 << 8 | c2;
00414 return 0;
00415 }
00416
00417
00418
00426 int write_int16(uint16 val, dbFILE * f)
00427 {
00428 if (fputc((val >> 8) & 0xFF, f->fp) == EOF
00429 || fputc(val & 0xFF, f->fp) == EOF) {
00430 return -1;
00431 }
00432 return 0;
00433 }
00434
00435
00436
00444 int read_int32(uint32 * ret, dbFILE * f)
00445 {
00446 int c1, c2, c3, c4;
00447
00448 c1 = fgetc(f->fp);
00449 c2 = fgetc(f->fp);
00450 c3 = fgetc(f->fp);
00451 c4 = fgetc(f->fp);
00452 if (c1 == EOF || c2 == EOF || c3 == EOF || c4 == EOF)
00453 return -1;
00454 *ret = c1 << 24 | c2 << 16 | c3 << 8 | c4;
00455 return 0;
00456 }
00457
00458
00459
00467 int write_int32(uint32 val, dbFILE * f)
00468 {
00469 if (fputc((val >> 24) & 0xFF, f->fp) == EOF)
00470 return -1;
00471 if (fputc((val >> 16) & 0xFF, f->fp) == EOF)
00472 return -1;
00473 if (fputc((val >> 8) & 0xFF, f->fp) == EOF)
00474 return -1;
00475 if (fputc((val) & 0xFF, f->fp) == EOF)
00476 return -1;
00477 return 0;
00478 }
00479
00480
00481
00489 int read_ptr(void **ret, dbFILE * f)
00490 {
00491 int c;
00492
00493 c = fgetc(f->fp);
00494 if (c == EOF)
00495 return -1;
00496 *ret = (c ? (void *) 1 : (void *) 0);
00497 return 0;
00498 }
00499
00500
00501
00509 int write_ptr(const void *ptr, dbFILE * f)
00510 {
00511 if (fputc(ptr ? 1 : 0, f->fp) == EOF)
00512 return -1;
00513 return 0;
00514 }
00515
00516
00517
00525 int read_string(char **ret, dbFILE * f)
00526 {
00527 char *s;
00528 uint16 len;
00529
00530 if (read_int16(&len, f) < 0)
00531 return -1;
00532 if (len == 0) {
00533 *ret = NULL;
00534 return 0;
00535 }
00536 s = scalloc(len, 1);
00537 if (len != fread(s, 1, len, f->fp)) {
00538 free(s);
00539 return -1;
00540 }
00541 *ret = s;
00542 return 0;
00543 }
00544
00545
00546
00554 int write_string(const char *s, dbFILE * f)
00555 {
00556 uint32 len;
00557
00558 if (!s)
00559 return write_int16(0, f);
00560 len = strlen(s);
00561 if (len > 65534)
00562 len = 65534;
00563 if (write_int16((uint16) (len + 1), f) < 0)
00564 return -1;
00565 if (len > 0 && fwrite(s, 1, len, f->fp) != len)
00566 return -1;
00567 if (fputc(0, f->fp) == EOF)
00568 return -1;
00569 return 0;
00570 }
00571
00572
00573
00581 static void rename_database(char *name, char *ext)
00582 {
00583
00584 char destpath[PATH_MAX];
00585
00586 snprintf(destpath, sizeof(destpath), "backups/%s.%s", name, ext);
00587 if (rename(name, destpath) != 0) {
00588 alog("Backup of %s failed.", name);
00589 anope_cmd_global(s_OperServ, "WARNING! Backup of %s failed.",
00590 name);
00591 }
00592 }
00593
00594
00595
00601 static void remove_backups(void)
00602 {
00603
00604 char ext[9];
00605 char path[PATH_MAX];
00606
00607 time_t t;
00608 struct tm tm;
00609
00610 time(&t);
00611 t -= (60 * 60 * 24 * KeepBackups);
00612 tm = *localtime(&t);
00613 strftime(ext, sizeof(ext), "%Y%m%d", &tm);
00614
00615 snprintf(path, sizeof(path), "backups/%s.%s", NickDBName, ext);
00616 #ifndef _WIN32
00617 unlink(path);
00618 #else
00619 DeleteFile(path);
00620 #endif
00621 snprintf(path, sizeof(path), "backups/%s.%s", ChanDBName, ext);
00622 #ifndef _WIN32
00623 unlink(path);
00624 #else
00625 DeleteFile(path);
00626 #endif
00627 snprintf(path, sizeof(path), "backups/%s.%s", OperDBName, ext);
00628 #ifndef _WIN32
00629 unlink(path);
00630 #else
00631 DeleteFile(path);
00632 #endif
00633 snprintf(path, sizeof(path), "backups/%s.%s", NewsDBName, ext);
00634 #ifndef _WIN32
00635 unlink(path);
00636 #else
00637 DeleteFile(path);
00638 #endif
00639 snprintf(path, sizeof(path), "backups/%s.%s", ExceptionDBName, ext);
00640 #ifndef _WIN32
00641 unlink(path);
00642 #else
00643 DeleteFile(path);
00644 #endif
00645
00646 if (s_BotServ) {
00647 snprintf(path, sizeof(path), "backups/%s.%s", BotDBName, ext);
00648 #ifndef _WIN32
00649 unlink(path);
00650 #else
00651 DeleteFile(path);
00652 #endif
00653 }
00654 if (s_HostServ) {
00655 snprintf(path, sizeof(path), "backups/%s.%s", HostDBName, ext);
00656 #ifndef _WIN32
00657 unlink(path);
00658 #else
00659 DeleteFile(path);
00660 #endif
00661 }
00662 if (NSEmailReg) {
00663 snprintf(path, sizeof(path), "backups/%s.%s", PreNickDBName, ext);
00664 #ifndef _WIN32
00665 unlink(path);
00666 #else
00667 DeleteFile(path);
00668 #endif
00669 }
00670 }
00671
00672
00673
00679 void backup_databases(void)
00680 {
00681
00682 time_t t;
00683 struct tm tm;
00684
00685 if (!KeepBackups) {
00686 return;
00687 }
00688
00689 time(&t);
00690 tm = *localtime(&t);
00691
00692 if (!curday) {
00693 curday = tm.tm_yday;
00694 return;
00695 }
00696
00697 if (curday != tm.tm_yday) {
00698
00699 char ext[9];
00700
00701 send_event(EVENT_DB_BACKUP, 1, EVENT_START);
00702 alog("Backing up databases");
00703
00704 remove_backups();
00705
00706 curday = tm.tm_yday;
00707 strftime(ext, sizeof(ext), "%Y%m%d", &tm);
00708
00709 if (!skeleton) {
00710 rename_database(NickDBName, ext);
00711 if (s_BotServ) {
00712 rename_database(BotDBName, ext);
00713 }
00714 rename_database(ChanDBName, ext);
00715 if (s_HostServ) {
00716 rename_database(HostDBName, ext);
00717 }
00718 if (NSEmailReg) {
00719 rename_database(PreNickDBName, ext);
00720 }
00721 }
00722
00723 rename_database(OperDBName, ext);
00724 rename_database(NewsDBName, ext);
00725 rename_database(ExceptionDBName, ext);
00726 send_event(EVENT_DB_BACKUP, 1, EVENT_STOP);
00727 }
00728 }
00729
00730
00731
00732 void ModuleDatabaseBackup(char *dbname)
00733 {
00734 char ext[9];
00735 time_t t;
00736 struct tm tm;
00737
00738 if (!KeepBackups) {
00739 return;
00740 }
00741
00742 time(&t);
00743 tm = *localtime(&t);
00744
00745 if (debug)
00746 alog("Module Database Backing up %s", dbname);
00747 ModuleRemoveBackups(dbname);
00748 curday = tm.tm_yday;
00749 strftime(ext, sizeof(ext), "%Y%m%d", &tm);
00750 rename_database(dbname, ext);
00751 }
00752
00753
00754
00755 void ModuleRemoveBackups(char *dbname)
00756 {
00757 char ext[9];
00758 char path[PATH_MAX];
00759
00760 time_t t;
00761 struct tm tm;
00762
00763 time(&t);
00764 t -= (60 * 60 * 24 * KeepBackups);
00765 tm = *localtime(&t);
00766 strftime(ext, sizeof(ext), "%Y%m%d", &tm);
00767
00768 snprintf(path, sizeof(path), "backups/%s.%s", dbname, ext);
00769 #ifndef _WIN32
00770 unlink(path);
00771 #else
00772 DeleteFile(path);
00773 #endif
00774 }
00775
00776