ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/conf_db.c
Revision: 1621
Committed: Wed Oct 31 23:11:40 2012 UTC (11 years, 5 months ago) by michael
Content type: text/x-csrc
File size: 13467 byte(s)
Log Message:
- src/conf_db.c: Cleanup get_file_version()

File Contents

# Content
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 }