datafiles.c

Go to the documentation of this file.
00001 /* Database file handling routines.
00002  *
00003  * (C) 2003-2013 Anope Team
00004  * Contact us at team@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  *
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     /* Get the current working directory: */
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     /* Use open() to avoid people sneaking a new file in under us */
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");   /* will fail and return NULL if fd < 0 */
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         /* Then the Lord said unto Moses, thou shalt free what thou hast malloced
00271          * -- codemastr */
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;             /* Did we manage to restore the old file? */
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 /*************************************************************************/