00001
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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"
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>
00039 #include <string.h>
00040
00041 using std::string;
00042
00043
00044 #define FLINT_VERSION 200709120
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
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
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
00133
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 }