xapian-core  1.4.27
chert_version.cc
Go to the documentation of this file.
1 
4 /* Copyright (C) 2006,2007,2008,2009,2013 Olly Betts
5  * Copyright 2010 Richard Boulton
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
22 #include <config.h>
23 
24 #include <xapian/error.h>
25 
26 #include "chert_version.h"
27 #include "io_utils.h"
28 #include "stringutils.h" // For STRINGIZE() and CONST_STRLEN().
29 #include "str.h"
30 
31 #include <cerrno>
32 #include <cstring> // For memcmp() and memcpy().
33 #include <string>
34 
35 #include "backends/uuids.h"
36 
37 using namespace std;
38 
39 // YYYYMMDDX where X allows multiple format revisions in a day
40 #define CHERT_VERSION 200912150
41 // 200804180 Chert debuts.
42 // 200903070 1.1.0 doclen bounds and wdf upper bound.
43 // 200912150 1.1.4 shorter position, postlist, record and termlist keys.
44 
45 #define MAGIC_STRING "IAmChert"
46 
47 #define MAGIC_LEN CONST_STRLEN(MAGIC_STRING)
48 // 4 for the version number; 16 for the UUID.
49 #define VERSIONFILE_SIZE (MAGIC_LEN + 4 + 16)
50 
51 // Literal version of VERSIONFILE_SIZE, used for error message. This needs
52 // to be updated by hand should VERSIONFILE_SIZE change, but that rarely
53 // happens so this isn't an onerous requirement.
54 #define VERSIONFILE_SIZE_LITERAL 28
55 
56 void
58 {
59  char buf[VERSIONFILE_SIZE] = MAGIC_STRING;
60  unsigned char *v = reinterpret_cast<unsigned char *>(buf) + MAGIC_LEN;
61  v[0] = static_cast<unsigned char>(CHERT_VERSION & 0xff);
62  v[1] = static_cast<unsigned char>((CHERT_VERSION >> 8) & 0xff);
63  v[2] = static_cast<unsigned char>((CHERT_VERSION >> 16) & 0xff);
64  v[3] = static_cast<unsigned char>((CHERT_VERSION >> 24) & 0xff);
65 
66  uuid.generate();
67  memcpy(buf + MAGIC_LEN + 4, uuid.data(), 16);
68 
69  int fd = ::open(filename.c_str(), O_WRONLY|O_CREAT|O_TRUNC|O_BINARY|O_CLOEXEC, 0666);
70 
71  if (fd < 0) {
72  string msg("Failed to create chert version file: ");
73  msg += filename;
74  throw Xapian::DatabaseOpeningError(msg, errno);
75  }
76 
77  try {
78  io_write(fd, buf, VERSIONFILE_SIZE);
79  } catch (...) {
80  (void)close(fd);
81  throw;
82  }
83 
84  io_sync(fd);
85  if (close(fd) != 0) {
86  string msg("Failed to create chert version file: ");
87  msg += filename;
88  throw Xapian::DatabaseOpeningError(msg, errno);
89  }
90 }
91 
92 void
94 {
95  int fd = ::open(filename.c_str(), O_RDONLY|O_BINARY|O_CLOEXEC);
96 
97  if (fd < 0) {
98  string msg = filename;
99  msg += ": Failed to open chert version file for reading";
100  if (errno == ENOENT || errno == ENOTDIR) {
101  throw Xapian::DatabaseNotFoundError(msg, errno);
102  }
103  throw Xapian::DatabaseOpeningError(msg, errno);
104  }
105 
106  // Try to read an extra byte so we know if the file is too long.
107  char buf[VERSIONFILE_SIZE + 1];
108  size_t size;
109  try {
110  size = io_read(fd, buf, VERSIONFILE_SIZE + 1);
111  } catch (...) {
112  (void)close(fd);
113  throw;
114  }
115  (void)close(fd);
116 
117  if (size != VERSIONFILE_SIZE) {
119  "VERSIONFILE_SIZE_LITERAL needs updating");
120  string msg = filename;
121  msg += ": Chert version file should be "
122  STRINGIZE(VERSIONFILE_SIZE_LITERAL)" bytes, actually ";
123  msg += str(size);
124  throw Xapian::DatabaseCorruptError(msg);
125  }
126 
127  if (memcmp(buf, MAGIC_STRING, MAGIC_LEN) != 0) {
128  string msg = filename;
129  msg += ": Chert version file doesn't contain the right magic string";
130  throw Xapian::DatabaseCorruptError(msg);
131  }
132 
133  const unsigned char *v;
134  v = reinterpret_cast<const unsigned char *>(buf) + MAGIC_LEN;
135  unsigned int version = v[0] | (v[1] << 8) | (v[2] << 16) | (v[3] << 24);
136  if (version != CHERT_VERSION) {
137  string msg = filename;
138  msg += ": Chert version file is version ";
139  msg += str(version);
140  msg += " but I only understand " STRINGIZE(CHERT_VERSION);
141  throw Xapian::DatabaseVersionError(msg);
142  }
143 
144  uuid.assign(buf + MAGIC_LEN + 4);
145 }
int close(FD &fd)
Definition: fd.h:63
void io_write(int fd, const char *p, size_t n)
Write n bytes from block pointed to by p to file descriptor fd.
Definition: io_utils.cc:145
void read_and_check()
Read the version file and check it&#39;s a version we understand.
#define VERSIONFILE_SIZE_LITERAL
DatabaseOpeningError indicates failure to open a database.
Definition: error.h:581
bool io_sync(int fd)
Ensure all data previously written to file descriptor fd has been written to disk.
Definition: io_utils.h:73
#define O_BINARY
Definition: safefcntl.h:81
WritableDatabase open()
Construct a WritableDatabase object for a new, empty InMemory database.
Definition: dbfactory.h:104
#define STRINGIZE(X)
The STRINGIZE macro converts its parameter into a string constant.
Definition: stringutils.h:36
STL namespace.
Convert types to std::string.
#define O_CLOEXEC
Definition: safefcntl.h:90
#define MAGIC_LEN
Hierarchy of classes which Xapian can throw as exceptions.
#define CHERT_VERSION
#define MAGIC_STRING
string str(int value)
Convert int to std::string.
Definition: str.cc:90
size_t io_read(int fd, char *p, size_t n, size_t min)
Read n bytes (or until EOF) into block pointed to by p from file descriptor fd.
Definition: io_utils.cc:123
Indicates an attempt to access a database not present.
Definition: error.h:1055
DatabaseVersionError indicates that a database is in an unsupported format.
Definition: error.h:632
DatabaseCorruptError indicates database corruption was detected.
Definition: error.h:409
void create()
Create the version file.
ChertVersion class.
Wrappers for low-level POSIX I/O routines.
Various handy helpers which std::string really should provide.
Class for handling UUIDs.
#define VERSIONFILE_SIZE