1 |
/* |
2 |
* ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). |
3 |
* |
4 |
* Copyright (C) 1996-2002 by Andrew Church <achurch@achurch.org> |
5 |
* Copyright (C) 2012 by the Hybrid Development Team. |
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 |
20 |
* USA |
21 |
*/ |
22 |
|
23 |
/*! \file conf_db.c |
24 |
* \brief Includes file utilities for database handling |
25 |
* \version $Id: conf_db.c 1569 2012-10-16 18:46:53Z michael $ |
26 |
*/ |
27 |
|
28 |
#include "stdinc.h" |
29 |
#include "conf_db.h" |
30 |
#include "memory.h" |
31 |
#include "client.h" |
32 |
#include "log.h" |
33 |
#include "send.h" |
34 |
#include "irc_string.h" |
35 |
|
36 |
|
37 |
/*! \brief Return the version number on the file. Return 0 if there is no version |
38 |
* number or the number doesn't make sense (i.e. less than 1 or greater |
39 |
* than FILE_VERSION). |
40 |
* |
41 |
* \param f dbFile Struct Member |
42 |
* \return int 0 if failure, 1 > is the version number |
43 |
*/ |
44 |
uint32_t |
45 |
get_file_version(struct dbFILE *f) |
46 |
{ |
47 |
uint32_t version = 0; |
48 |
|
49 |
if (read_uint32(&version, f) == -1) |
50 |
{ |
51 |
ilog(LOG_TYPE_IRCD, "Error reading version number on %s: %s", |
52 |
f->filename, strerror(errno)); |
53 |
return 0; |
54 |
} |
55 |
|
56 |
if (version < 1) |
57 |
{ |
58 |
ilog(LOG_TYPE_IRCD, "Invalid version number (%u) on %s", |
59 |
version, f->filename); |
60 |
return 0; |
61 |
} |
62 |
|
63 |
return version; |
64 |
} |
65 |
|
66 |
/*! \brief Write the current version number to the file. |
67 |
* \param f dbFile Struct Member |
68 |
* \return 0 on error, 1 on success. |
69 |
*/ |
70 |
int |
71 |
write_file_version(struct dbFILE *f, uint32_t version) |
72 |
{ |
73 |
if (write_uint32(version, f) == -1) |
74 |
{ |
75 |
ilog(LOG_TYPE_IRCD, "Error writing version number on %s", |
76 |
f->filename); |
77 |
return 0; |
78 |
} |
79 |
|
80 |
return 1; |
81 |
} |
82 |
|
83 |
/*! \brief Open the database for reading |
84 |
* \param service If error whom to return the error as |
85 |
* \param filename File to open as the database |
86 |
* \return dbFile struct |
87 |
*/ |
88 |
static struct dbFILE * |
89 |
open_db_read(const char *service, const char *filename) |
90 |
{ |
91 |
struct dbFILE *f = MyMalloc(sizeof(*f)); |
92 |
FILE *fp = NULL; |
93 |
|
94 |
strlcpy(f->filename, filename, sizeof(f->filename)); |
95 |
|
96 |
f->mode = 'r'; |
97 |
fp = fopen(f->filename, "rb"); |
98 |
|
99 |
if (!fp) |
100 |
{ |
101 |
int errno_save = errno; |
102 |
|
103 |
if (errno != ENOENT) |
104 |
ilog(LOG_TYPE_IRCD, "Can not read %s database %s", service, |
105 |
f->filename); |
106 |
|
107 |
MyFree(f); |
108 |
errno = errno_save; |
109 |
return NULL; |
110 |
} |
111 |
|
112 |
f->fp = fp; |
113 |
f->backupfp = NULL; |
114 |
|
115 |
return f; |
116 |
} |
117 |
|
118 |
/*! \brief Open the database for writting |
119 |
* \param service If error whom to return the error as |
120 |
* \param filename File to open as the database |
121 |
* \param version Database Version |
122 |
* \return dbFile struct |
123 |
*/ |
124 |
static struct dbFILE * |
125 |
open_db_write(const char *service, const char *filename, |
126 |
uint32_t version) |
127 |
{ |
128 |
struct dbFILE *f = MyMalloc(sizeof(*f)); |
129 |
int fd = 0; |
130 |
|
131 |
strlcpy(f->filename, filename, sizeof(f->filename)); |
132 |
|
133 |
filename = f->filename; |
134 |
f->mode = 'w'; |
135 |
|
136 |
snprintf(f->backupname, sizeof(f->backupname), "%s.save", filename); |
137 |
|
138 |
if (!*f->backupname || !strcmp(f->backupname, filename)) |
139 |
{ |
140 |
int errno_save = errno; |
141 |
|
142 |
ilog(LOG_TYPE_IRCD, "Opening %s database %s for write: Filename too long", |
143 |
service, filename); |
144 |
MyFree(f); |
145 |
errno = errno_save; |
146 |
return NULL; |
147 |
} |
148 |
|
149 |
unlink(filename); |
150 |
|
151 |
f->backupfp = fopen(filename, "rb"); |
152 |
|
153 |
if (rename(filename, f->backupname) < 0 && errno != ENOENT) |
154 |
{ |
155 |
int errno_save = errno; |
156 |
static int walloped = 0; |
157 |
|
158 |
if (!walloped++) |
159 |
sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE, |
160 |
"Can not back up %s database %s", |
161 |
service, filename); |
162 |
|
163 |
errno = errno_save; |
164 |
ilog(LOG_TYPE_IRCD, "Can not back up %s database %s", service, filename); |
165 |
|
166 |
if (f->backupfp) |
167 |
fclose(f->backupfp); |
168 |
|
169 |
MyFree(f); |
170 |
errno = errno_save; |
171 |
return NULL; |
172 |
} |
173 |
|
174 |
unlink(filename); |
175 |
|
176 |
/* Use open() to avoid people sneaking a new file in under us */ |
177 |
fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0666); |
178 |
f->fp = fdopen(fd, "wb"); /* will fail and return NULL if fd < 0 */ |
179 |
|
180 |
if (!f->fp || !write_file_version(f, version)) |
181 |
{ |
182 |
int errno_save = errno; |
183 |
static int walloped = 0; |
184 |
|
185 |
if (!walloped++) |
186 |
sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE, |
187 |
"Can't write to %s database %s", |
188 |
service, filename); |
189 |
|
190 |
errno = errno_save; |
191 |
ilog(LOG_TYPE_IRCD, "Can't write to %s database %s", |
192 |
service, filename); |
193 |
|
194 |
if (f->fp) |
195 |
{ |
196 |
fclose(f->fp); |
197 |
unlink(filename); |
198 |
} |
199 |
|
200 |
if (f->backupname[0] && rename(f->backupname, filename) < 0) |
201 |
ilog(LOG_TYPE_IRCD, "Cannot restore backup copy of %s", |
202 |
filename); |
203 |
|
204 |
MyFree(f); |
205 |
errno = errno_save; |
206 |
return NULL; |
207 |
} |
208 |
|
209 |
return f; |
210 |
} |
211 |
|
212 |
/*! \brief Open a database file for reading (*mode == 'r') or writing (*mode == 'w'). |
213 |
* Return the stream pointer, or NULL on error. When opening for write, it |
214 |
* is an error for rename() to return an error (when backing up the original |
215 |
* file) other than ENOENT, if NO_BACKUP_OKAY is not defined; it is an error |
216 |
* if the version number cannot be written to the file; and it is a fatal |
217 |
* error if opening the file for write fails and the backup was successfully |
218 |
* made but cannot be restored. |
219 |
* |
220 |
* \param service If error whom to return the error as |
221 |
* \param filename File to open as the database |
222 |
* \param mode Mode for writting or reading |
223 |
* \param version Database Version |
224 |
* \return dbFile struct |
225 |
*/ |
226 |
struct dbFILE * |
227 |
open_db(const char *service, const char *filename, |
228 |
const char *mode, uint32_t version) |
229 |
{ |
230 |
switch (*mode) |
231 |
{ |
232 |
case 'r': |
233 |
return open_db_read(service, filename); |
234 |
break; |
235 |
case 'w': |
236 |
return open_db_write(service, filename, version); |
237 |
break; |
238 |
default: |
239 |
errno = EINVAL; |
240 |
return NULL; |
241 |
} |
242 |
} |
243 |
|
244 |
/*! \brief Restore the database file to its condition before open_db(). This is |
245 |
* identical to close_db() for files open for reading; however, for files |
246 |
* open for writing, we first attempt to restore any backup file before |
247 |
* closing files. |
248 |
* |
249 |
* \param dbFile struct |
250 |
*/ |
251 |
void |
252 |
restore_db(struct dbFILE *f) |
253 |
{ |
254 |
int errno_save = errno; |
255 |
|
256 |
if (f->mode == 'w') |
257 |
{ |
258 |
int ok = 0; /* Did we manage to restore the old file? */ |
259 |
|
260 |
errno = errno_save = 0; |
261 |
|
262 |
if (f->backupname[0] && strcmp(f->backupname, f->filename)) |
263 |
if (rename(f->backupname, f->filename) == 0) |
264 |
ok = 1; |
265 |
|
266 |
if (!ok && f->backupfp) |
267 |
{ |
268 |
char buf[1024]; |
269 |
size_t i; |
270 |
|
271 |
ok = fseek(f->fp, 0, SEEK_SET) == 0; |
272 |
|
273 |
while (ok && (i = fread(buf, 1, sizeof(buf), f->backupfp)) > 0) |
274 |
if (fwrite(buf, 1, i, f->fp) != i) |
275 |
ok = 0; |
276 |
|
277 |
if (ok) |
278 |
{ |
279 |
fflush(f->fp); |
280 |
ftruncate(fileno(f->fp), ftell(f->fp)); |
281 |
} |
282 |
} |
283 |
|
284 |
if (!ok && errno > 0) |
285 |
ilog(LOG_TYPE_IRCD, "Unable to restore backup of %s", f->filename); |
286 |
|
287 |
errno_save = errno; |
288 |
|
289 |
if (f->backupfp) |
290 |
fclose(f->backupfp); |
291 |
if (f->backupname[0]) |
292 |
unlink(f->backupname); |
293 |
} |
294 |
|
295 |
fclose(f->fp); |
296 |
|
297 |
if (!errno_save) |
298 |
errno_save = errno; |
299 |
|
300 |
MyFree(f); |
301 |
errno = errno_save; |
302 |
} |
303 |
|
304 |
/*! \brief Close a database file. If the file was opened for write, remove the |
305 |
* backup we (may have) created earlier. |
306 |
* |
307 |
* \param dbFile struct |
308 |
*/ |
309 |
void |
310 |
close_db(struct dbFILE *f) |
311 |
{ |
312 |
if (f->mode == 'w' && f->backupname[0] && |
313 |
strcmp(f->backupname, f->filename)) |
314 |
{ |
315 |
if (f->backupfp) |
316 |
fclose(f->backupfp); |
317 |
|
318 |
unlink(f->backupname); |
319 |
} |
320 |
|
321 |
fclose(f->fp); |
322 |
MyFree(f); |
323 |
} |
324 |
|
325 |
/* |
326 |
* Read and write 2-, 4- and 8-byte quantities, pointers, and strings. All |
327 |
* multibyte values are stored in big-endian order (most significant byte |
328 |
* first). A pointer is stored as a byte, either 0 if NULL or 1 if not, |
329 |
* and read pointers are returned as either (void *)0 or (void *)1. A |
330 |
* string is stored with a 2-byte unsigned length (including the trailing |
331 |
* \0) first; a length of 0 indicates that the string pointer is NULL. |
332 |
* Written strings are truncated silently at 65534 bytes, and are always |
333 |
* null-terminated. |
334 |
*/ |
335 |
|
336 |
/*! \brief Read a unsigned 8bit integer |
337 |
* |
338 |
* \param ret 8bit integer to read |
339 |
* \param dbFile struct |
340 |
* \return -1 on error, 0 otherwise. |
341 |
*/ |
342 |
int |
343 |
read_uint8(unsigned char *ret, struct dbFILE *f) |
344 |
{ |
345 |
int c = fgetc(f->fp); |
346 |
|
347 |
if (c == EOF) |
348 |
return -1; |
349 |
|
350 |
*ret = c; |
351 |
return 0; |
352 |
} |
353 |
|
354 |
/*! \brief Write a 8bit integer |
355 |
* |
356 |
* \param ret 8bit integer to write |
357 |
* \param dbFile struct |
358 |
* \return -1 on error, 0 otherwise. |
359 |
*/ |
360 |
int |
361 |
write_uint8(unsigned char val, struct dbFILE *f) |
362 |
{ |
363 |
if (fputc(val, f->fp) == EOF) |
364 |
return -1; |
365 |
|
366 |
return 0; |
367 |
} |
368 |
|
369 |
/*! \brief Read a unsigned 8bit integer |
370 |
* |
371 |
* \param ret 8bit integer to read |
372 |
* \param dbFile struct |
373 |
* \return -1 on error, 0 otherwise. |
374 |
*/ |
375 |
int |
376 |
read_uint16(uint16_t *ret, struct dbFILE *f) |
377 |
{ |
378 |
int c1 = fgetc(f->fp); |
379 |
int c2 = fgetc(f->fp); |
380 |
|
381 |
if (c1 == EOF || c2 == EOF) |
382 |
return -1; |
383 |
|
384 |
*ret = c1 << 8 | c2; |
385 |
return 0; |
386 |
} |
387 |
|
388 |
/*! \brief Write a unsigned 16bit integer |
389 |
* |
390 |
* \param ret 16bit integer to write |
391 |
* \param dbFile struct |
392 |
* \return -1 on error, 0 otherwise. |
393 |
*/ |
394 |
int |
395 |
write_uint16(uint16_t val, struct dbFILE *f) |
396 |
{ |
397 |
if (fputc((val >> 8) & 0xFF, f->fp) == EOF || |
398 |
fputc(val & 0xFF, f->fp) == EOF) |
399 |
return -1; |
400 |
|
401 |
return 0; |
402 |
} |
403 |
|
404 |
/*! \brief Read a unsigned 32bit integer |
405 |
* |
406 |
* \param ret unsigned 32bit integer to read |
407 |
* \param dbFile struct |
408 |
* \return -1 on error, 0 otherwise. |
409 |
*/ |
410 |
int |
411 |
read_uint32(uint32_t *ret, struct dbFILE *f) |
412 |
{ |
413 |
int c1 = fgetc(f->fp); |
414 |
int c2 = fgetc(f->fp); |
415 |
int c3 = fgetc(f->fp); |
416 |
int c4 = fgetc(f->fp); |
417 |
|
418 |
if (c1 == EOF || c2 == EOF || c3 == EOF || c4 == EOF) |
419 |
return -1; |
420 |
|
421 |
*ret = c1 << 24 | c2 << 16 | c3 << 8 | c4; |
422 |
return 0; |
423 |
} |
424 |
|
425 |
|
426 |
/*! \brief Write a unsigned 32bit integer |
427 |
* |
428 |
* \param ret unsigned 32bit integer to write |
429 |
* \param dbFile struct |
430 |
* \return -1 on error, 0 otherwise. |
431 |
*/ |
432 |
int |
433 |
write_uint32(uint32_t val, struct dbFILE *f) |
434 |
{ |
435 |
if (fputc((val >> 24) & 0xFF, f->fp) == EOF) |
436 |
return -1; |
437 |
if (fputc((val >> 16) & 0xFF, f->fp) == EOF) |
438 |
return -1; |
439 |
if (fputc((val >> 8) & 0xFF, f->fp) == EOF) |
440 |
return -1; |
441 |
if (fputc((val) & 0xFF, f->fp) == EOF) |
442 |
return -1; |
443 |
return 0; |
444 |
} |
445 |
|
446 |
/*! \brief Read a unsigned 64bit integer |
447 |
* |
448 |
* \param ret unsigned 64bit integer to read |
449 |
* \param dbFile struct |
450 |
* \return -1 on error, 0 otherwise. |
451 |
*/ |
452 |
int |
453 |
read_uint64(uint64_t *ret, struct dbFILE *f) |
454 |
{ |
455 |
int64_t c1 = fgetc(f->fp); |
456 |
int64_t c2 = fgetc(f->fp); |
457 |
int64_t c3 = fgetc(f->fp); |
458 |
int64_t c4 = fgetc(f->fp); |
459 |
int64_t c5 = fgetc(f->fp); |
460 |
int64_t c6 = fgetc(f->fp); |
461 |
int64_t c7 = fgetc(f->fp); |
462 |
int64_t c8 = fgetc(f->fp); |
463 |
|
464 |
if (c1 == EOF || c2 == EOF || c3 == EOF || c4 == EOF || |
465 |
c5 == EOF || c6 == EOF || c7 == EOF || c8 == EOF) |
466 |
return -1; |
467 |
|
468 |
*ret = c1 << 56 | c2 << 48 | c3 << 40 | c4 << 32 | |
469 |
c5 << 24 | c6 << 16 | c7 << 8 | c8; |
470 |
return 0; |
471 |
} |
472 |
|
473 |
|
474 |
/*! \brief Write a unsigned 64bit integer |
475 |
* |
476 |
* \param ret unsigned 64bit integer to write |
477 |
* \param dbFile struct |
478 |
* \return -1 on error, 0 otherwise. |
479 |
*/ |
480 |
int |
481 |
write_uint64(uint64_t val, struct dbFILE *f) |
482 |
{ |
483 |
if (fputc((val >> 56) & 0xFF, f->fp) == EOF) |
484 |
return -1; |
485 |
if (fputc((val >> 48) & 0xFF, f->fp) == EOF) |
486 |
return -1; |
487 |
if (fputc((val >> 40) & 0xFF, f->fp) == EOF) |
488 |
return -1; |
489 |
if (fputc((val >> 32) & 0xFF, f->fp) == EOF) |
490 |
return -1; |
491 |
if (fputc((val >> 24) & 0xFF, f->fp) == EOF) |
492 |
return -1; |
493 |
if (fputc((val >> 16) & 0xFF, f->fp) == EOF) |
494 |
return -1; |
495 |
if (fputc((val >> 8) & 0xFF, f->fp) == EOF) |
496 |
return -1; |
497 |
if (fputc((val) & 0xFF, f->fp) == EOF) |
498 |
return -1; |
499 |
return 0; |
500 |
} |
501 |
|
502 |
/*! \brief Read Pointer |
503 |
* |
504 |
* \param ret pointer to read |
505 |
* \param dbFile struct |
506 |
* \return -1 on error, 0 otherwise. |
507 |
*/ |
508 |
int |
509 |
read_ptr(void **ret, struct dbFILE *f) |
510 |
{ |
511 |
int c = fgetc(f->fp); |
512 |
|
513 |
if (c == EOF) |
514 |
return -1; |
515 |
|
516 |
*ret = (c ? (void *)1 : (void *)0); |
517 |
return 0; |
518 |
} |
519 |
|
520 |
|
521 |
/*! \brief Write Pointer |
522 |
* |
523 |
* \param ret pointer to write |
524 |
* \param dbFile struct |
525 |
* \return -1 on error, 0 otherwise. |
526 |
*/ |
527 |
int |
528 |
write_ptr(const void *ptr, struct dbFILE *f) |
529 |
{ |
530 |
if (fputc(ptr ? 1 : 0, f->fp) == EOF) |
531 |
return -1; |
532 |
return 0; |
533 |
} |
534 |
|
535 |
/*! \brief Read String |
536 |
* |
537 |
* \param ret string |
538 |
* \param dbFile struct |
539 |
* \return -1 on error, 0 otherwise. |
540 |
*/ |
541 |
int |
542 |
read_string(char **ret, struct dbFILE *f) |
543 |
{ |
544 |
char *s = NULL; |
545 |
uint16_t len = 0; |
546 |
|
547 |
if (read_uint16(&len, f) < 0) |
548 |
return -1; |
549 |
|
550 |
if (len == 0) |
551 |
{ |
552 |
*ret = NULL; |
553 |
return 0; |
554 |
} |
555 |
|
556 |
s = MyMalloc(len); |
557 |
|
558 |
if (len != fread(s, 1, len, f->fp)) |
559 |
{ |
560 |
MyFree(s); |
561 |
return -1; |
562 |
} |
563 |
|
564 |
*ret = s; |
565 |
return 0; |
566 |
} |
567 |
|
568 |
/*! \brief Write String |
569 |
* |
570 |
* \param ret string |
571 |
* \param dbFile struct |
572 |
* \return -1 on error, 0 otherwise. |
573 |
*/ |
574 |
int |
575 |
write_string(const char *s, struct dbFILE *f) |
576 |
{ |
577 |
uint32_t len = 0; |
578 |
|
579 |
if (!s) |
580 |
return write_uint16(0, f); |
581 |
|
582 |
len = strlen(s); |
583 |
|
584 |
if (len > 65534) |
585 |
len = 65534; |
586 |
if (write_uint16((uint16_t)(len + 1), f) < 0) |
587 |
return -1; |
588 |
if (len > 0 && fwrite(s, 1, len, f->fp) != len) |
589 |
return -1; |
590 |
if (fputc(0, f->fp) == EOF) |
591 |
return -1; |
592 |
|
593 |
return 0; |
594 |
} |