00001
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <config.h>
00023
00024 #include "safeerrno.h"
00025
00026 #include <xapian/error.h>
00027
00028 #include "brass_version.h"
00029 #include "io_utils.h"
00030 #include "omassert.h"
00031 #include "stringutils.h"
00032 #include "str.h"
00033
00034 #ifdef __WIN32__
00035 # include "msvc_posix_wrapper.h"
00036 #endif
00037
00038 #include <cstdio>
00039 #include <cstring>
00040 #include <string>
00041
00042 #include "common/safeuuid.h"
00043
00044 using namespace std;
00045
00046
00047 #define BRASS_VERSION 201103110
00048
00049
00050
00051 #define MAGIC_STRING "IAmBrass"
00052
00053 #define MAGIC_LEN CONST_STRLEN(MAGIC_STRING)
00054
00055 #define VERSIONFILE_SIZE (MAGIC_LEN + 4 + 16)
00056
00057
00058
00059
00060 #define VERSIONFILE_SIZE_LITERAL 28
00061
00062 void
00063 BrassVersion::create()
00064 {
00065 char buf[VERSIONFILE_SIZE] = MAGIC_STRING;
00066 unsigned char *v = reinterpret_cast<unsigned char *>(buf) + MAGIC_LEN;
00067 v[0] = static_cast<unsigned char>(BRASS_VERSION & 0xff);
00068 v[1] = static_cast<unsigned char>((BRASS_VERSION >> 8) & 0xff);
00069 v[2] = static_cast<unsigned char>((BRASS_VERSION >> 16) & 0xff);
00070 v[3] = static_cast<unsigned char>((BRASS_VERSION >> 24) & 0xff);
00071
00072 uuid_generate(uuid);
00073 memcpy(buf + MAGIC_LEN + 4, (void*)uuid, 16);
00074
00075 int fd = ::open(filename.c_str(), O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0666);
00076
00077 if (fd < 0) {
00078 string msg("Failed to create brass version file: ");
00079 msg += filename;
00080 throw Xapian::DatabaseOpeningError(msg, errno);
00081 }
00082
00083 try {
00084 io_write(fd, buf, VERSIONFILE_SIZE);
00085 } catch (...) {
00086 (void)close(fd);
00087 throw;
00088 }
00089
00090 if (close(fd) != 0) {
00091 string msg("Failed to create brass version file: ");
00092 msg += filename;
00093 throw Xapian::DatabaseOpeningError(msg, errno);
00094 }
00095 }
00096
00097 void
00098 BrassVersion::read_and_check()
00099 {
00100 int fd = ::open(filename.c_str(), O_RDONLY|O_BINARY);
00101
00102 if (fd < 0) {
00103 string msg = filename;
00104 msg += ": Failed to open brass version file for reading";
00105 throw Xapian::DatabaseOpeningError(msg, errno);
00106 }
00107
00108
00109 char buf[VERSIONFILE_SIZE + 1];
00110 size_t size;
00111 try {
00112 size = io_read(fd, buf, VERSIONFILE_SIZE + 1, 0);
00113 } catch (...) {
00114 (void)close(fd);
00115 throw;
00116 }
00117 (void)close(fd);
00118
00119 if (size != VERSIONFILE_SIZE) {
00120 CompileTimeAssert(VERSIONFILE_SIZE == VERSIONFILE_SIZE_LITERAL);
00121 string msg = filename;
00122 msg += ": Brass version file should be "
00123 STRINGIZE(VERSIONFILE_SIZE_LITERAL)" bytes, actually ";
00124 msg += str(size);
00125 throw Xapian::DatabaseCorruptError(msg);
00126 }
00127
00128 if (memcmp(buf, MAGIC_STRING, MAGIC_LEN) != 0) {
00129 string msg = filename;
00130 msg += ": Brass version file doesn't contain the right magic string";
00131 throw Xapian::DatabaseCorruptError(msg);
00132 }
00133
00134 const unsigned char *v;
00135 v = reinterpret_cast<const unsigned char *>(buf) + MAGIC_LEN;
00136 unsigned int version = v[0] | (v[1] << 8) | (v[2] << 16) | (v[3] << 24);
00137 if (version != BRASS_VERSION) {
00138 string msg = filename;
00139 msg += ": Brass version file is version ";
00140 msg += str(version);
00141 msg += " but I only understand "STRINGIZE(BRASS_VERSION);
00142 throw Xapian::DatabaseVersionError(msg);
00143 }
00144
00145 memcpy((void*)uuid, buf + MAGIC_LEN + 4, 16);
00146 }