diff options
author | michael <michael@82007160-df01-0410-b94d-b575c5fd34c7> | 2012-11-19 21:28:28 +0000 |
---|---|---|
committer | michael <michael@82007160-df01-0410-b94d-b575c5fd34c7> | 2012-11-19 21:28:28 +0000 |
commit | ed37ac064d4ce8611e2af0ddcf416139cd887395 (patch) | |
tree | 856da1e2110d27cb98aee2c7560ac5f58d95377e | |
parent | 3e1b0138a8d550aadee2e78b094f6dfb2a7a82aa (diff) |
- conf_db.c: import backup/restore cleanups from 5.1.24
git-svn-id: svn://svn.ircd-hybrid.org/svnroot/ircd-hybrid/trunk@1668 82007160-df01-0410-b94d-b575c5fd34c7
-rw-r--r-- | include/conf_db.h | 14 | ||||
-rw-r--r-- | src/conf_db.c | 209 |
2 files changed, 83 insertions, 140 deletions
diff --git a/include/conf_db.h b/include/conf_db.h index 8d8b5ef..7cdc555 100644 --- a/include/conf_db.h +++ b/include/conf_db.h @@ -1,7 +1,7 @@ /* * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). * - * Copyright (C) 1996-2002 by Andrew Church <achurch@achurch.org> + * Copyright (C) 1996-2009 by Andrew Church <achurch@achurch.org> * Copyright (C) 2012 by the Hybrid Development Team. * * This program is free software; you can redistribute it and/or modify @@ -30,21 +30,19 @@ struct dbFILE { - int mode; /**< 'r' for reading, 'w' for writing */ - FILE *fp; /**< The normal file descriptor */ - FILE *backupfp; /**< Open file pointer to a backup copy of - * the database file (if non-NULL) */ + char mode; /**< 'r' for reading, 'w' for writing */ + FILE *fp; /**< The file pointer itself */ char filename[PATH_MAX + 1]; /**< Name of the database file */ - char backupname[PATH_MAX + 1]; /**< Name of the backup file */ + char tempname[PATH_MAX + 1]; /**< Name of the temporary file (for writing) */ }; extern void check_file_version(struct dbFILE *); extern uint32_t get_file_version(struct dbFILE *); extern int write_file_version(struct dbFILE *, uint32_t); -extern struct dbFILE *open_db(const char *, const char *, const char *, uint32_t); +extern struct dbFILE *open_db(const char *, const char *, uint32_t); extern void restore_db(struct dbFILE *); /* Restore to state before open_db() */ -extern void close_db(struct dbFILE *); +extern int close_db(struct dbFILE *); extern void backup_databases(void); #define read_db(f,buf,len) (fread((buf),1,(len),(f)->fp)) diff --git a/src/conf_db.c b/src/conf_db.c index a51eb21..798fd14 100644 --- a/src/conf_db.c +++ b/src/conf_db.c @@ -1,7 +1,7 @@ /* * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). * - * Copyright (C) 1996-2002 by Andrew Church <achurch@achurch.org> + * Copyright (C) 1996-2009 by Andrew Church <achurch@achurch.org> * Copyright (C) 2012 by the Hybrid Development Team. * * This program is free software; you can redistribute it and/or modify @@ -88,7 +88,7 @@ write_file_version(struct dbFILE *f, uint32_t version) * \return dbFile struct */ static struct dbFILE * -open_db_read(const char *service, const char *filename) +open_db_read(const char *filename) { struct dbFILE *f = MyMalloc(sizeof(*f)); FILE *fp = NULL; @@ -103,8 +103,7 @@ open_db_read(const char *service, const char *filename) int errno_save = errno; if (errno != ENOENT) - ilog(LOG_TYPE_IRCD, "Can't read %s database %s", service, - f->filename); + ilog(LOG_TYPE_IRCD, "Can't read database file %s", f->filename); MyFree(f); errno = errno_save; @@ -112,20 +111,16 @@ open_db_read(const char *service, const char *filename) } f->fp = fp; - f->backupfp = NULL; - return f; } /*! \brief Open the database for writting - * \param service If error whom to return the error as * \param filename File to open as the database * \param version Database Version * \return dbFile struct */ static struct dbFILE * -open_db_write(const char *service, const char *filename, - uint32_t version) +open_db_write(const char *filename, uint32_t version) { struct dbFILE *f = MyMalloc(sizeof(*f)); int fd = 0; @@ -135,48 +130,22 @@ open_db_write(const char *service, const char *filename, filename = f->filename; f->mode = 'w'; - snprintf(f->backupname, sizeof(f->backupname), "%s.save", filename); + snprintf(f->tempname, sizeof(f->tempname), "%s.new", filename); - if (!*f->backupname || !strcmp(f->backupname, filename)) + if (f->tempname[0] == '\0' || !strcmp(f->tempname, filename)) { - int errno_save = errno; - - ilog(LOG_TYPE_IRCD, "Opening %s database %s for write: Filename too long", - service, filename); + ilog(LOG_TYPE_IRCD, "Opening database file %s for write: Filename too long", + filename); MyFree(f); - errno = errno_save; + errno = ENAMETOOLONG; return NULL; } - unlink(filename); - - f->backupfp = fopen(filename, "rb"); - - if (rename(filename, f->backupname) < 0 && errno != ENOENT) - { - int errno_save = errno; - static int walloped = 0; - - if (!walloped++) - sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE, - "Can't back up %s database %s", - service, filename); - - errno = errno_save; - ilog(LOG_TYPE_IRCD, "Can't back up %s database %s", service, filename); - - if (f->backupfp) - fclose(f->backupfp); - - MyFree(f); - errno = errno_save; - return NULL; - } - - unlink(filename); + remove(f->tempname); /* Use open() to avoid people sneaking a new file in under us */ - if ((fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0666)) >= 0) + fd = open(f->tempname, O_WRONLY | O_CREAT | O_EXCL, 0666); + if (fd >= 0) f->fp = fdopen(fd, "wb"); if (!f->fp || !write_file_version(f, version)) @@ -186,56 +155,49 @@ open_db_write(const char *service, const char *filename, if (!walloped++) sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE, - "Can't write to %s database %s", - service, filename); + "Can't create temporary database file %s", + f->tempname); errno = errno_save; - ilog(LOG_TYPE_IRCD, "Can't write to %s database %s", - service, filename); + ilog(LOG_TYPE_IRCD, "Can't create temporary database file %s", + f->tempname); if (f->fp) - { fclose(f->fp); - unlink(filename); - } - if (f->backupname[0] && rename(f->backupname, filename) < 0) - ilog(LOG_TYPE_IRCD, "Can't restore backup copy of %s", - filename); + remove(f->tempname); + MyFree(f); - MyFree(f); - errno = errno_save; - return NULL; + errno = errno_save; + return NULL; } return f; } /*! \brief Open a database file for reading (*mode == 'r') or writing (*mode == 'w'). - * Return the stream pointer, or NULL on error. When opening for write, it - * is an error for rename() to return an error (when backing up the original - * file) other than ENOENT, if NO_BACKUP_OKAY is not defined; it is an error - * if the version number cannot be written to the file; and it is a fatal - * error if opening the file for write fails and the backup was successfully - * made but cannot be restored. + * Return the stream pointer, or NULL on error. When opening for write, the + * file actually opened is a temporary file, which will be renamed to the + * original file on close. + * + * `version' is only used when opening a file for writing, and indicates the + * version number to write to the file. * - * \param service If error whom to return the error as * \param filename File to open as the database * \param mode Mode for writting or reading * \param version Database Version * \return dbFile struct */ struct dbFILE * -open_db(const char *service, const char *filename, - const char *mode, uint32_t version) +open_db(const char *filename, const char *mode, uint32_t version) { switch (*mode) { case 'r': - return open_db_read(service, filename); + return open_db_read(filename); break; case 'w': - return open_db_write(service, filename, version); + return open_db_write(filename, version); break; default: errno = EINVAL; @@ -243,10 +205,10 @@ open_db(const char *service, const char *filename, } } -/*! \brief Restore the database file to its condition before open_db(). This is +/*! \brief Restore the database file to its condition before open_db(). This is * identical to close_db() for files open for reading; however, for files - * open for writing, we first attempt to restore any backup file before - * closing files. + * open for writing, we discard the new temporary file instead of renaming + * it over the old file. The value of errno is preserved. * * \param dbFile struct */ @@ -255,73 +217,56 @@ restore_db(struct dbFILE *f) { int errno_save = errno; - if (f->mode == 'w') - { - int ok = 0; /* Did we manage to restore the old file? */ - - errno = errno_save = 0; - - if (f->backupname[0] && strcmp(f->backupname, f->filename)) - if (rename(f->backupname, f->filename) == 0) - ok = 1; - - if (!ok && f->backupfp) - { - char buf[1024]; - size_t i; - - ok = fseek(f->fp, 0, SEEK_SET) == 0; - - while (ok && (i = fread(buf, 1, sizeof(buf), f->backupfp)) > 0) - if (fwrite(buf, 1, i, f->fp) != i) - ok = 0; - - if (ok) - { - fflush(f->fp); - ftruncate(fileno(f->fp), ftell(f->fp)); - } - } - - if (!ok && errno > 0) - ilog(LOG_TYPE_IRCD, "Unable to restore backup of %s", f->filename); - - errno_save = errno; - - if (f->backupfp) - fclose(f->backupfp); - if (f->backupname[0]) - unlink(f->backupname); - } - - fclose(f->fp); - - if (!errno_save) - errno_save = errno; + if (f->fp) + fclose(f->fp); + if (f->mode == 'w' && f->tempname[0]) + remove(f->tempname); MyFree(f); errno = errno_save; } -/*! \brief Close a database file. If the file was opened for write, remove the - * backup we (may have) created earlier. +/*! \brief Close a database file. If the file was opened for write, moves the new + * file over the old one, and logs/wallops an error message if the rename() + * fails. * * \param dbFile struct */ -void +int close_db(struct dbFILE *f) { - if (f->mode == 'w' && f->backupname[0] && - strcmp(f->backupname, f->filename)) + int res; + + if (!f->fp) { - if (f->backupfp) - fclose(f->backupfp); + errno = EINVAL; + return -1; + } - unlink(f->backupname); + res = fclose(f->fp); + f->fp = NULL; + + if (res != 0) + return -1; + + if (f->mode == 'w' && f->tempname[0] && strcmp(f->tempname, f->filename)) + { + if (rename(f->tempname, f->filename) < 0) + { + int errno_save = errno; + + sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE, "Unable to move new " + "data to database file %s; new data NOT saved.", + f->filename); + errno = errno_save; + ilog(LOG_TYPE_IRCD, "Unable to move new data to database file %s; new " + "data NOT saved.", f->filename); + remove(f->tempname); + } } - fclose(f->fp); MyFree(f); + return 0; } /* @@ -617,7 +562,7 @@ save_kline_database(void) struct dbFILE *f = NULL; dlink_node *ptr = NULL; - if (!(f = open_db("kline", KPATH, "w", KLINE_DB_VERSION))) + if (!(f = open_db(KPATH, "w", KLINE_DB_VERSION))) return; for (i = 0; i < ATABLE_SIZE; ++i) @@ -666,7 +611,7 @@ load_kline_database(void) uint64_t field_4 = 0; uint64_t field_5 = 0; - if (!(f = open_db("kline", KPATH, "r", KLINE_DB_VERSION))) + if (!(f = open_db(KPATH, "r", KLINE_DB_VERSION))) return; if (get_file_version(f) < 1) @@ -707,7 +652,7 @@ save_dline_database(void) struct dbFILE *f = NULL; dlink_node *ptr = NULL; - if (!(f = open_db("dline", DLPATH, "w", KLINE_DB_VERSION))) + if (!(f = open_db(DLPATH, "w", KLINE_DB_VERSION))) return; for (i = 0; i < ATABLE_SIZE; ++i) @@ -754,7 +699,7 @@ load_dline_database(void) uint64_t field_3 = 0; uint64_t field_4 = 0; - if (!(f = open_db("dline", DLPATH, "r", KLINE_DB_VERSION))) + if (!(f = open_db(DLPATH, "r", KLINE_DB_VERSION))) return; if (get_file_version(f) < 1) @@ -793,7 +738,7 @@ save_gline_database(void) struct dbFILE *f = NULL; dlink_node *ptr = NULL; - if (!(f = open_db("gline", GPATH, "w", KLINE_DB_VERSION))) + if (!(f = open_db(GPATH, "w", KLINE_DB_VERSION))) return; for (i = 0; i < ATABLE_SIZE; ++i) @@ -842,7 +787,7 @@ load_gline_database(void) uint64_t field_4 = 0; uint64_t field_5 = 0; - if (!(f = open_db("gline", GPATH, "r", KLINE_DB_VERSION))) + if (!(f = open_db(GPATH, "r", KLINE_DB_VERSION))) return; if (get_file_version(f) < 1) @@ -883,7 +828,7 @@ save_resv_database(void) dlink_node *ptr = NULL; struct MaskItem *conf = NULL; - if (!(f = open_db("resv", RESVPATH, "w", KLINE_DB_VERSION))) + if (!(f = open_db(RESVPATH, "w", KLINE_DB_VERSION))) return; DLINK_FOREACH(ptr, resv_channel_list.head) @@ -944,7 +889,7 @@ load_resv_database(void) char *reason = NULL; struct MaskItem *conf = NULL; - if (!(f = open_db("resv", RESVPATH, "r", KLINE_DB_VERSION))) + if (!(f = open_db(RESVPATH, "r", KLINE_DB_VERSION))) return; if (get_file_version(f) < 1) @@ -996,7 +941,7 @@ save_xline_database(void) dlink_node *ptr = NULL; struct MaskItem *conf = NULL; - if (!(f = open_db("xline", XPATH, "w", KLINE_DB_VERSION))) + if (!(f = open_db(XPATH, "w", KLINE_DB_VERSION))) return; DLINK_FOREACH(ptr, xconf_items.head) @@ -1036,7 +981,7 @@ load_xline_database(void) char *reason = NULL; struct MaskItem *conf = NULL; - if (!(f = open_db("xline", XPATH, "r", KLINE_DB_VERSION))) + if (!(f = open_db(XPATH, "r", KLINE_DB_VERSION))) return; if (get_file_version(f) < 1) |