Coverage Report

Created: 2023-12-08 06:12

/src/gdbm/src/gdbmload.c
Line
Count
Source (jump to first uncovered line)
1
/* This file is part of GDBM, the GNU data base manager.
2
   Copyright (C) 2011-2023 Free Software Foundation, Inc.
3
4
   GDBM is free software; you can redistribute it and/or modify
5
   it under the terms of the GNU General Public License as published by
6
   the Free Software Foundation; either version 3, or (at your option)
7
   any later version.
8
9
   GDBM is distributed in the hope that it will be useful,
10
   but WITHOUT ANY WARRANTY; without even the implied warranty of
11
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
   GNU General Public License for more details.
13
14
   You should have received a copy of the GNU General Public License
15
   along with GDBM. If not, see <http://www.gnu.org/licenses/>.   */
16
17
# include "autoconf.h"
18
# include "gdbmdefs.h"
19
# include "gdbm.h"
20
# include <sys/types.h>
21
# include <pwd.h>
22
# include <grp.h>
23
24
struct datbuf
25
{
26
  unsigned char *buffer;
27
  size_t size;
28
};
29
30
struct dump_file
31
{
32
  FILE *fp;
33
  size_t line;
34
35
  char *linebuf;
36
  size_t lbsize;
37
  size_t lblevel;
38
  
39
  char *buffer;
40
  size_t bufsize;
41
  size_t buflevel;
42
43
  size_t parmc;
44
45
  struct datbuf data[2];
46
  char *header;
47
};
48
49
static void
50
dump_file_free (struct dump_file *file)
51
0
{
52
0
  free (file->linebuf);
53
0
  free (file->buffer);
54
0
  free (file->data[0].buffer);
55
0
  free (file->data[1].buffer);
56
0
  free (file->header);
57
0
}
58
59
static const char *
60
getparm (const char *buf, const char *parm)
61
0
{
62
0
  if (!buf)
63
0
    return NULL;
64
0
  while (*buf)
65
0
    {
66
0
      const char *p;
67
0
      for (p = parm; *p == *buf; p++, buf++)
68
0
  ;
69
0
      if (*p == 0 && *buf == '=')
70
0
  return buf + 1;
71
0
      buf += strlen (buf) + 1;
72
0
    }
73
0
  return NULL;
74
0
}
75
76
static size_t
77
get_dump_line (struct dump_file *file)
78
0
{
79
0
  char buf[80];
80
  
81
0
  if (file->lblevel == 0)
82
0
    {
83
0
      while (fgets (buf, sizeof buf, file->fp))
84
0
  {
85
0
    size_t n = strlen (buf);
86
    
87
0
    if (buf[n-1] == '\n')
88
0
      {
89
0
        file->line++;
90
0
        --n;
91
0
      }
92
    
93
0
    if (n + 1 + file->lblevel > file->lbsize)
94
0
      {
95
0
        size_t s = ((file->lblevel + n + _GDBM_MAX_DUMP_LINE_LEN)
96
0
        / _GDBM_MAX_DUMP_LINE_LEN)
97
0
              * _GDBM_MAX_DUMP_LINE_LEN;
98
0
        char *newp = realloc (file->linebuf, s);
99
0
        if (!newp)
100
0
    return GDBM_MALLOC_ERROR;
101
0
        file->linebuf = newp;
102
0
        file->lbsize = s;
103
0
      }
104
    
105
0
    memcpy (file->linebuf + file->lblevel, buf, n);
106
0
    file->lblevel += n;
107
0
    if (buf[n])
108
0
      {
109
0
        file->linebuf[file->lblevel] = 0;
110
0
        break;
111
0
      }
112
0
  }
113
0
    }
114
0
  return file->lblevel;
115
0
}
116
117
static int
118
get_data (struct dump_file *file)
119
0
{
120
0
  size_t n;
121
122
0
  file->buflevel = 0;
123
0
  file->parmc = 0;
124
  
125
0
  while ((n = get_dump_line (file)))
126
0
    {
127
0
      if (file->linebuf[0] == '#')
128
0
  return 0;
129
0
      if (n + file->buflevel > file->bufsize)
130
0
  {
131
0
    size_t s = ((file->buflevel + n + _GDBM_MAX_DUMP_LINE_LEN - 1)
132
0
          / _GDBM_MAX_DUMP_LINE_LEN)
133
0
                * _GDBM_MAX_DUMP_LINE_LEN;
134
0
    char *newp = realloc (file->buffer, s);
135
0
    if (!newp)
136
0
      return GDBM_MALLOC_ERROR;
137
0
    file->buffer = newp;
138
0
    file->bufsize = s;
139
0
  }
140
0
      memcpy (file->buffer + file->buflevel, file->linebuf, n);
141
0
      file->buflevel += n;
142
0
      file->lblevel = 0;
143
0
    }
144
0
  return ferror (file->fp) ? GDBM_FILE_READ_ERROR : 0;
145
0
}
146
147
static int
148
get_parms (struct dump_file *file)
149
0
{
150
0
  size_t n;
151
152
0
  file->buflevel = 0;
153
0
  file->parmc = 0;
154
0
  while ((n = get_dump_line (file)))
155
0
    {
156
0
      char *p;
157
158
0
      p = file->linebuf;
159
0
      if (*p != '#')
160
0
  return 0;
161
0
      if (n == 0 || *++p != ':')
162
0
  {
163
0
    file->lblevel = 0;
164
0
    continue;
165
0
  }
166
0
      if (--n == 0)
167
0
  {
168
0
    file->lblevel = 0;
169
0
    continue;
170
0
  }
171
      
172
0
      if (n + 1 + file->buflevel > file->bufsize)
173
0
  {
174
0
    size_t s = ((file->buflevel + n + _GDBM_MAX_DUMP_LINE_LEN)
175
0
          / _GDBM_MAX_DUMP_LINE_LEN)
176
0
                * _GDBM_MAX_DUMP_LINE_LEN;
177
0
    char *newp = realloc (file->buffer, s);
178
0
    if (!newp)
179
0
      return GDBM_MALLOC_ERROR;
180
0
    file->buffer = newp;
181
0
    file->bufsize = s;
182
0
  }
183
184
0
      while (*p)
185
0
  {
186
0
    p++;
187
0
    while (*p == ' ' || *p == '\t')
188
0
      p++;
189
0
    if (*p)
190
0
      {
191
0
        while (*p && *p != '=')
192
0
    file->buffer[file->buflevel++] = *p++;
193
        
194
0
        if (*p == '=')
195
0
    {
196
0
      file->buffer[file->buflevel++] = *p++;
197
0
      if (*p == '"')
198
0
        {
199
0
          p++;
200
0
          while (*p && *p != '"')
201
0
      file->buffer[file->buflevel++] = *p++;
202
203
0
          if (*p == '"')
204
0
      p++;
205
0
        }
206
0
      else
207
0
        {
208
0
          while (!(*p == 0 || *p == ','))
209
0
      file->buffer[file->buflevel++] = *p++;
210
0
        }
211
0
      file->parmc++;
212
0
      file->buffer[file->buflevel++] = 0;
213
0
    }
214
0
        else
215
0
    return GDBM_MALFORMED_DATA;
216
0
      }
217
0
    else
218
0
      break;
219
0
  }
220
0
      file->lblevel = 0;
221
0
    }
222
223
0
  if (file->buffer)
224
0
    file->buffer[file->buflevel] = 0;
225
  
226
0
  return ferror (file->fp) ? GDBM_FILE_READ_ERROR : 0;
227
0
}
228
229
static int
230
get_len (const char *param, size_t *plen)
231
0
{
232
0
  unsigned long n;
233
0
  const char *p = getparm (param, "len");
234
0
  char *end;
235
  
236
0
  if (!p)
237
0
    return GDBM_ITEM_NOT_FOUND;
238
239
0
  errno = 0;
240
0
  n = strtoul (p, &end, 10);
241
0
  if (*end == 0 && errno == 0)
242
0
    {
243
0
      *plen = n;
244
0
      return 0;
245
0
    }
246
247
0
  return GDBM_MALFORMED_DATA;
248
0
}
249
250
static int
251
read_record (struct dump_file *file, char *param, int n, datum *dat)
252
0
{
253
0
  int rc;
254
0
  size_t len, consumed_size, decoded_size;
255
256
0
  if (!param)
257
0
    {
258
0
      rc = get_parms (file);
259
0
      if (rc)
260
0
  return rc;
261
0
      if (file->parmc == 0)
262
0
  return GDBM_ITEM_NOT_FOUND;
263
0
      param = file->buffer;
264
0
    }
265
0
  rc = get_len (param, &len);
266
0
  if (rc)
267
0
    return rc;
268
0
  dat->dsize = len; /* FIXME: data type mismatch */
269
0
  rc = get_data (file);
270
0
  if (rc)
271
0
    return rc;
272
273
0
  rc = _gdbm_base64_decode ((unsigned char *)file->buffer, file->buflevel,
274
0
          &file->data[n].buffer, &file->data[n].size,
275
0
          &consumed_size, &decoded_size);
276
0
  if (rc)
277
0
    return rc;
278
0
  if (consumed_size != file->buflevel || decoded_size != len)
279
0
    return GDBM_MALFORMED_DATA;
280
0
  dat->dptr = (void*) file->data[n].buffer;
281
0
  return 0;
282
0
}
283
284
0
#define META_UID  0x01
285
0
#define META_GID  0x02
286
0
#define META_MODE 0x04
287
288
static int
289
_set_gdbm_meta_info (GDBM_FILE dbf, char *param, int meta_mask)
290
0
{
291
0
  unsigned long n;
292
0
  uid_t owner_uid;
293
0
  uid_t owner_gid;
294
0
  mode_t mode;
295
0
  int meta_flags = 0;
296
0
  const char *p;
297
0
  char *end;
298
299
0
  if (!(meta_mask & GDBM_META_MASK_OWNER))
300
0
    {
301
0
      p = getparm (param, "user");
302
0
      if (p)
303
0
  {
304
0
    struct passwd *pw = getpwnam (p);
305
0
    if (pw)
306
0
      {
307
0
        owner_uid = pw->pw_uid;
308
0
        meta_flags |= META_UID;
309
0
      }
310
0
  }
311
312
0
      if (!(meta_flags & META_UID) && (p = getparm (param, "uid")))
313
0
  {
314
0
    errno = 0;
315
0
    n = strtoul (p, &end, 10);
316
0
    if (*end == 0 && errno == 0)
317
0
      {
318
0
        owner_uid = n;
319
0
        meta_flags |= META_UID;
320
0
      }
321
0
  }
322
323
0
      p = getparm (param, "group");
324
0
      if (p)
325
0
  {
326
0
    struct group *gr = getgrnam (p);
327
0
    if (gr)
328
0
      {
329
0
        owner_gid = gr->gr_gid;
330
0
        meta_flags |= META_GID;
331
0
      }
332
0
  }
333
0
      if (!(meta_flags & META_GID) && (p = getparm (param, "gid")))
334
0
  {
335
0
    errno = 0;
336
0
    n = strtoul (p, &end, 10);
337
0
    if (*end == 0 && errno == 0)
338
0
      {
339
0
        owner_gid = n;
340
0
        meta_flags |= META_GID;
341
0
      }
342
0
  }
343
0
    }
344
  
345
0
  if (!(meta_mask & GDBM_META_MASK_MODE))
346
0
    {
347
0
      p = getparm (param, "mode");
348
0
      if (p)
349
0
  {
350
0
    errno = 0;
351
0
    n = strtoul (p, &end, 8);
352
0
    if (*end == 0 && errno == 0)
353
0
      {
354
0
        mode = n & 0777;
355
0
        meta_flags |= META_MODE;
356
0
      }
357
0
  }
358
0
    }
359
  
360
0
  if (meta_flags)
361
0
    {
362
0
      int fd = gdbm_fdesc (dbf);
363
0
      if (getuid () == 0 && (meta_flags & (META_UID|META_GID)))
364
0
  {
365
0
    if ((meta_flags & (META_UID|META_GID)) != (META_UID|META_GID))
366
0
      {
367
0
        struct stat st;
368
0
        if (fstat (fd, &st))
369
0
    {
370
0
      GDBM_SET_ERRNO (dbf, GDBM_FILE_STAT_ERROR, FALSE);
371
0
      return 1;
372
0
    }
373
0
        if (!(meta_flags & META_UID))
374
0
    owner_uid = st.st_uid;
375
0
        if (!(meta_flags & META_GID))
376
0
    owner_gid = st.st_gid;
377
0
      }
378
0
    if (fchown (fd, owner_uid, owner_gid))
379
0
      {
380
0
        GDBM_SET_ERRNO (dbf, GDBM_ERR_FILE_OWNER, FALSE);
381
0
        return 1;
382
0
      }
383
0
  }
384
0
      if ((meta_flags & META_MODE) && fchmod (fd, mode))
385
0
  {
386
0
    GDBM_SET_ERRNO (dbf, GDBM_ERR_FILE_OWNER, FALSE);
387
0
    return 1;
388
0
  }
389
0
    }
390
0
  return 0;
391
0
}
392
393
int
394
_gdbm_str2fmt (char const *str)
395
8.96k
{
396
8.96k
  if (strcmp (str, "numsync") == 0)
397
0
    return GDBM_NUMSYNC;
398
8.96k
  if (strcmp (str, "standard") == 0)
399
8.96k
    return 0;
400
0
  return -1;
401
8.96k
}
402
403
static int
404
_gdbm_load_file (struct dump_file *file, GDBM_FILE dbf, GDBM_FILE *ofp,
405
     int replace, int meta_mask)
406
0
{
407
0
  char *param = NULL;
408
0
  int rc;
409
0
  GDBM_FILE tmp = NULL;
410
0
  int format = 0;
411
0
  const char *p;
412
  
413
0
  rc = get_parms (file);
414
0
  if (rc)
415
0
    return rc;
416
  
417
0
  if (file->parmc)
418
0
    {
419
0
      file->header = file->buffer;
420
0
      file->buffer = NULL;
421
0
      file->bufsize = file->buflevel = 0;
422
0
    }
423
0
  else
424
0
    return GDBM_MALFORMED_DATA;
425
426
0
  if ((p = getparm (file->header, "format")) != NULL)
427
0
    {
428
0
      int n = _gdbm_str2fmt (p);
429
0
      if (n != -1)
430
0
  format = n;
431
      /* FIXME: other values silently ignored */
432
0
    }
433
      
434
0
  if (!dbf)
435
0
    {
436
0
      int flags = replace ? GDBM_WRCREAT : GDBM_NEWDB;
437
0
      const char *filename = getparm (file->header, "file");
438
      
439
0
      if (!filename)
440
0
  return GDBM_NO_DBNAME;
441
442
0
      tmp = gdbm_open (filename, 0, flags | format, 0600, NULL);
443
0
      if (!tmp)
444
0
  return gdbm_errno;
445
0
      dbf = tmp;
446
0
    }
447
448
0
  if (format)
449
0
    {
450
      /*
451
       * If the database is already in the requested format, the call to
452
       * gdbm_convert will return 0 immediately.
453
       */
454
0
      if (gdbm_convert (dbf, format))
455
0
  { 
456
0
    rc = gdbm_errno;
457
0
    if (tmp)
458
0
      gdbm_close (tmp);
459
0
    return rc;
460
0
  }
461
0
    }   
462
  
463
0
  param = file->header;
464
0
  while (1)
465
0
    {
466
0
      datum key, content;
467
0
      rc = read_record (file, param, 0, &key);
468
0
      if (rc)
469
0
  {
470
0
    if (rc == GDBM_ITEM_NOT_FOUND && feof (file->fp))
471
0
      rc = 0;
472
0
    break;
473
0
  }
474
0
      param = NULL;
475
476
0
      rc = read_record (file, NULL, 1, &content);
477
0
      if (rc)
478
0
  break;
479
      
480
0
      if (gdbm_store (dbf, key, content, replace))
481
0
  {
482
0
    rc = gdbm_errno;
483
0
    break;
484
0
  }
485
0
    }
486
487
0
  if (rc == 0)
488
0
    {
489
0
      rc = _set_gdbm_meta_info (dbf, file->header, meta_mask);
490
0
      *ofp = dbf;
491
0
    }
492
0
  else if (tmp)
493
0
    gdbm_close (tmp);
494
    
495
0
  return rc;
496
0
}
497
498
static int
499
read_bdb_header (struct dump_file *file)
500
0
{    
501
0
  char buf[256];
502
  
503
0
  file->line = 1;
504
0
  if (!fgets (buf, sizeof (buf), file->fp))
505
0
    return -1;
506
0
  if (strcmp (buf, "VERSION=3\n"))
507
0
    return -1;
508
0
  while (fgets (buf, sizeof (buf), file->fp))
509
0
    {
510
0
      ++file->line;
511
0
      if (strcmp (buf, "HEADER=END\n") == 0)
512
0
  return 0;
513
0
    }
514
0
  return -1;
515
0
}
516
517
static int
518
c2x (int c)
519
0
{
520
0
  static char xdig[] = "0123456789abcdef";
521
0
  char *p = strchr (xdig, c);
522
0
  if (!p)
523
0
    return -1;
524
0
  return p - xdig;
525
0
} 
526
527
0
#define DINCR 128
528
529
static int
530
xdatum_read (FILE *fp, datum *d, size_t *pdmax)
531
0
{
532
0
  int c;
533
0
  size_t dmax = *pdmax;
534
  
535
0
  d->dsize = 0;
536
0
  while ((c = fgetc (fp)) != EOF && c != '\n')
537
0
    {
538
0
      int t, n;
539
      
540
0
      t = c2x (c);
541
0
      if (t == -1)
542
0
  return EOF;
543
0
      t <<= 4;
544
545
0
      if ((c = fgetc (fp)) == EOF)
546
0
  break;
547
    
548
0
      n = c2x (c);
549
0
      if (n == -1)
550
0
  return EOF;
551
0
      t += n;
552
553
0
      if (d->dsize == dmax)
554
0
  {
555
0
    char *np = realloc (d->dptr, dmax + DINCR);
556
0
    if (!np)
557
0
      return GDBM_MALLOC_ERROR;
558
0
    d->dptr = np;
559
0
    dmax += DINCR;
560
0
  }
561
0
      d->dptr[d->dsize++] = t;
562
0
    }
563
0
  *pdmax = dmax;
564
0
  if (c == '\n')
565
0
    return 0;
566
0
  return c;
567
0
}
568
569
static int
570
gdbm_load_bdb_dump (struct dump_file *file, GDBM_FILE dbf, int replace)
571
0
{
572
0
  datum xd[2];
573
0
  size_t xs[2];
574
0
  int rc, c;
575
0
  int i;
576
  
577
0
  if (read_bdb_header (file))
578
0
    return -1;
579
0
  memset (&xd, 0, sizeof (xd));
580
0
  xs[0] = xs[1] = 0;
581
0
  i = 0;
582
0
  rc = 0;
583
0
  while ((c = fgetc (file->fp)) == ' ')
584
0
    {
585
0
      rc = xdatum_read (file->fp, &xd[i], &xs[i]);
586
0
      if (rc)
587
0
  break;
588
0
      ++file->line;
589
590
0
      if (i == 1)
591
0
  {
592
0
    if (gdbm_store (dbf, xd[0], xd[1], replace))
593
0
      return gdbm_errno;
594
0
  }
595
0
      i = !i;
596
0
    }
597
  //FIXME: Read "DATA=END"
598
0
  free (xd[0].dptr);
599
0
  free (xd[1].dptr);
600
0
  if (rc == 0 && i)
601
0
    rc = EOF;
602
    
603
0
  return rc;
604
0
}
605
606
int
607
gdbm_load_from_file (GDBM_FILE *pdbf, FILE *fp, int replace,
608
         int meta_mask,
609
         unsigned long *line)
610
0
{
611
0
  struct dump_file df;
612
0
  int rc;
613
614
0
  if (!pdbf || !fp)
615
0
    return EINVAL;
616
617
  /* Guess input file format */
618
0
  rc = fgetc (fp);
619
0
  ungetc (rc, fp);
620
0
  if (rc == '!')
621
0
    {
622
0
      if (line)
623
0
  *line = 0;
624
0
      if (!*pdbf)
625
0
  {
626
0
    GDBM_SET_ERRNO (NULL, GDBM_NO_DBNAME, FALSE);
627
0
    return -1;
628
0
  }
629
0
      if (gdbm_import_from_file (*pdbf, fp, replace) == -1)
630
0
  return -1;
631
0
      return 0;
632
0
    }
633
634
0
  memset (&df, 0, sizeof df);
635
0
  df.fp = fp;
636
637
0
  if (rc == 'V')
638
0
    {
639
0
      if (!*pdbf)
640
0
  {
641
0
    GDBM_SET_ERRNO (NULL, GDBM_NO_DBNAME, FALSE);
642
0
    return -1;
643
0
  }
644
0
      rc = gdbm_load_bdb_dump (&df, *pdbf, replace);
645
0
    }
646
0
  else
647
0
    rc = _gdbm_load_file (&df, *pdbf, pdbf, replace, meta_mask);
648
0
  dump_file_free (&df);
649
0
  if (rc)
650
0
    {
651
0
      if (line)
652
0
  *line = df.line;
653
0
      GDBM_SET_ERRNO (NULL, rc, FALSE);
654
0
      return -1;
655
0
    }
656
0
  return 0;
657
0
}
658
659
int
660
gdbm_load (GDBM_FILE *pdbf, const char *filename, int replace,
661
     int meta_mask,
662
     unsigned long *line)
663
0
{
664
0
  FILE *fp;
665
0
  int rc;
666
  
667
0
  fp = fopen (filename, "r");
668
0
  if (!fp)
669
0
    {
670
0
      GDBM_SET_ERRNO (NULL, GDBM_FILE_OPEN_ERROR, FALSE);
671
0
      return -1;
672
0
    }
673
0
  rc = gdbm_load_from_file (pdbf, fp, replace, meta_mask, line);
674
0
  fclose (fp);
675
0
  return rc;
676
0
}
677