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