backends/flint/flint_version.cc

Go to the documentation of this file.
00001 
00004 /* Copyright (C) 2006,2007 Olly Betts
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00019  */
00020 
00021 #include <config.h>
00022 
00023 #include "safeerrno.h"
00024 
00025 #include <xapian/error.h>
00026 
00027 #include "flint_io.h"
00028 #include "flint_version.h"
00029 #include "stringutils.h" // For STRINGIZE() and CONST_STRLEN().
00030 #include "utils.h"
00031 
00032 #ifdef __WIN32__
00033 # include "msvc_posix_wrapper.h"
00034 #endif
00035 
00036 #include <string>
00037 
00038 #include <stdio.h> // For rename().
00039 #include <string.h> // for memcmp
00040 
00041 using std::string;
00042 
00043 // YYYYMMDDX where X allows multiple format revisions in a day
00044 #define FLINT_VERSION 200709120
00045 // 200709120 1.0.3 Database::get_metadata(), WritableDatabase::set_metadata().
00046 //                 Kill the unused "has_termfreqs" flag in the termlist table.
00047 // 200706140 1.0.2 Optional value and position tables.
00048 // 200704230 1.0.0 Use zlib compression of tags for record and termlist tables.
00049 // 200611200  N/A  Fixed occasional, architecture-dependent surplus bits in
00050 //                 interpolative coding; "flicklock" -> "flintlock".
00051 // 200506110 0.9.2 Fixed interpolative coding to work(!)
00052 // 200505310 0.9.1 Interpolative coding for position lists.
00053 // 200505280  N/A  Total doclen and last docid entry moved to postlist table.
00054 // 200505270  N/A  First dated version.
00055 
00056 #define MAGIC_STRING "IAmFlint"
00057 
00058 #define MAGIC_LEN CONST_STRLEN(MAGIC_STRING)
00059 #define VERSIONFILE_SIZE (MAGIC_LEN + 4)
00060 
00061 void FlintVersion::create()
00062 {
00063     char buf[VERSIONFILE_SIZE] = MAGIC_STRING;
00064     unsigned char *v = reinterpret_cast<unsigned char *>(buf) + MAGIC_LEN;
00065     v[0] = static_cast<unsigned char>(FLINT_VERSION & 0xff);
00066     v[1] = static_cast<unsigned char>((FLINT_VERSION >> 8) & 0xff);
00067     v[2] = static_cast<unsigned char>((FLINT_VERSION >> 16) & 0xff);
00068     v[3] = static_cast<unsigned char>((FLINT_VERSION >> 24) & 0xff);
00069 
00070     int fd = ::open(filename.c_str(), O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0666);
00071 
00072     if (fd < 0) {
00073         string msg("Failed to create flint version file: ");
00074         msg += filename;
00075         throw Xapian::DatabaseOpeningError(msg, errno);
00076     }
00077 
00078     try {
00079         flint_io_write(fd, buf, VERSIONFILE_SIZE);
00080     } catch (...) {
00081         (void)close(fd);
00082         throw;
00083     }
00084 
00085     if (close(fd) != 0) {
00086         string msg("Failed to create flint version file: ");
00087         msg += filename;
00088         throw Xapian::DatabaseOpeningError(msg, errno);
00089     }
00090 }
00091 
00092 void FlintVersion::read_and_check(bool readonly)
00093 {
00094     int fd = ::open(filename.c_str(), O_RDONLY|O_BINARY);
00095 
00096     if (fd < 0) {
00097         string msg("Failed to open flint version file for reading: ");
00098         msg += filename;
00099         throw Xapian::DatabaseOpeningError(msg, errno);
00100     }
00101 
00102     // Try to read an extra byte so we know if the file is too long.
00103     char buf[VERSIONFILE_SIZE + 1];
00104     size_t size;
00105     try {
00106         size = flint_io_read(fd, buf, VERSIONFILE_SIZE + 1, 0);
00107     } catch (...) {
00108         (void)close(fd);
00109         throw;
00110     }
00111     (void)close(fd);
00112 
00113     if (size != VERSIONFILE_SIZE) {
00114         string msg("Flint version file ");
00115         msg += filename;
00116         msg += " should be "STRINGIZE(VERSIONFILE_SIZE)" bytes, actually ";
00117         msg += om_tostring(size);
00118         throw Xapian::DatabaseCorruptError(msg);
00119     }
00120 
00121     if (memcmp(buf, MAGIC_STRING, MAGIC_LEN) != 0) {
00122         string msg("Flint version file doesn't contain the right magic string: ");
00123         msg += filename;
00124         throw Xapian::DatabaseCorruptError(msg);
00125     }
00126 
00127     const unsigned char *v;
00128     v = reinterpret_cast<const unsigned char *>(buf) + MAGIC_LEN;
00129     unsigned int version = v[0] | (v[1] << 8) | (v[2] << 16) | (v[3] << 24);
00130     if (version >= 200704230 && version < 200709120) {
00131         if (readonly) return;
00132         // Upgrade the database to the current version since any changes we
00133         // make won't be compatible with older versions of Xapian.
00134         string filename_save = filename;
00135         filename += ".tmp";
00136         create();
00137         int result;
00138 #ifdef __WIN32__
00139         result = msvc_posix_rename(filename.c_str(), filename_save.c_str());
00140 #else
00141         result = rename(filename.c_str(), filename_save.c_str());
00142 #endif
00143         filename = filename_save;
00144         if (result == -1) {
00145             string msg("Failed to update flint version file: ");
00146             msg += filename;
00147             throw Xapian::DatabaseOpeningError(msg);
00148         }
00149         return;
00150     }
00151     if (version != FLINT_VERSION) {
00152         string msg("Flint version file ");
00153         msg += filename;
00154         msg += " is version ";
00155         msg += om_tostring(version);
00156         msg += " but I only understand "STRINGIZE(FLINT_VERSION);
00157         throw Xapian::DatabaseVersionError(msg);
00158     }
00159 }

Documentation for Xapian (version 1.0.10).
Generated on 24 Dec 2008 by Doxygen 1.5.2.