datafiles.c

Go to the documentation of this file.
00001 /* Database file handling routines.
00002  *
00003  * (C) 2003-2007 Anope Team
00004  * Contact us at info@anope.org
00005  *
00006  * Please read COPYING and README for further details.
00007  *
00008  * Based on the original code of Epona by Lara.
00009  * Based on the original code of Services by Andy Church. 
00010  * 
00011  * $Id: datafiles.c 1265 2007-08-26 15:33:06Z geniusdex $ 
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     /* Get the current working directory: */
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     /* Use open() to avoid people sneaking a new file in under us */
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");   /* will fail and return NULL if fd < 0 */
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         /* Then the Lord said unto Moses, thou shalt free what thou hast malloced
00272          * -- codemastr */
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;             /* Did we manage to restore the old file? */
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 /*************************************************************************/

Generated on Sun Dec 30 09:26:48 2007 for Anope by  doxygen 1.5.1-20070107