]> mj.ucw.cz Git - libucw.git/blob - lib/db-tool.c
When processing the `-S' option, work on a copy, so that the command
[libucw.git] / lib / db-tool.c
1 /*
2  *      SDBM Database Utility
3  *
4  *      (c) 2000--2001 Martin Mares <mj@ucw.cz>
5  *
6  *      This software may be freely distributed and used according to the terms
7  *      of the GNU Lesser General Public License.
8  */
9
10 #include "lib/lib.h"
11 #include "lib/db.h"
12 #include "lib/db_internal.h"
13 #include "lib/fastbuf.h"
14
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <fcntl.h>
19 #include <unistd.h>
20 #include <errno.h>
21 #include <getopt.h>
22
23 static int verbose=0;
24 static int cache=1024;
25 static int force_key=-2;
26 static int force_val=-2;
27 static int force_page=-1;
28
29 #define SDBM_DUMP_MAGIC 0x321f120e
30 #define SDBM_DUMP_VERSION 1
31
32 static void
33 dump(char *db, char *dmp)
34 {
35   struct sdbm *src;
36   struct fastbuf *dest;
37   struct sdbm_options op;
38   int e, c=0;
39
40   bzero(&op, sizeof(op));
41   op.name = db;
42   op.cache_size = 16;
43   op.flags = 0;
44   src = sdbm_open(&op);
45   if (!src)
46     die("Source open failed: %m");
47
48   dest = bopen(dmp, O_WRONLY | O_CREAT | O_TRUNC, 65536);
49   bputl(dest, SDBM_DUMP_MAGIC);
50   bputl(dest, SDBM_DUMP_VERSION);
51   bputl(dest, src->page_order);
52   bputl(dest, src->key_size);
53   bputl(dest, src->val_size);
54
55   fprintf(stderr, "Dumping database...\n");
56   sdbm_rewind(src);
57   for(;;)
58     {
59       byte key[65536], val[65536];
60       int klen = sizeof(key);
61       int vlen = sizeof(val);
62       e = sdbm_get_next(src, key, &klen, val, &vlen);
63       if (!e)
64         break;
65       if (e < 0)
66         fprintf(stderr, "sdbm_get_next: error %d\n", e);
67       if (!(c++ % 1024))
68         {
69           fprintf(stderr, "%d\r", c);
70           fflush(stderr);
71         }
72       bputw(dest, klen);
73       bwrite(dest, key, klen);
74       bputw(dest, vlen);
75       bwrite(dest, val, vlen);
76     }
77
78   sdbm_close(src);
79   bclose(dest);
80   fprintf(stderr, "Dumped %d records\n", c);
81 }
82
83 static void
84 restore(char *dmp, char *db)
85 {
86   struct sdbm *dest;
87   struct fastbuf *src;
88   struct sdbm_options op;
89   int e, c=0;
90
91   src = bopen(dmp, O_RDONLY, 65536);
92   if (bgetl(src) != SDBM_DUMP_MAGIC ||
93       bgetl(src) != SDBM_DUMP_VERSION)
94     die("%s: not a sdbm dump", dmp);
95
96   bzero(&op, sizeof(op));
97   op.name = db;
98   e = unlink(op.name);
99   if (e < 0 && errno != ENOENT)
100     die("unlink: %m");
101   op.cache_size = cache;
102   op.flags = SDBM_CREAT | SDBM_WRITE | SDBM_FAST;
103   op.page_order = bgetl(src);
104   if (force_page >= 0)
105     op.page_order = force_page;
106   op.key_size = bgetl(src);
107   if (force_key >= 0)
108     op.key_size = force_key;
109   op.val_size = bgetl(src);
110   if (force_val >= 0)
111     op.val_size = force_val;
112   dest = sdbm_open(&op);
113   if (!dest)
114     die("Destination open failed");
115
116   fprintf(stderr, "Restoring database...\n");
117   for(;;)
118     {
119       byte key[65536], val[65536];
120       int klen, vlen;
121       klen = bgetw(src);
122       if (klen < 0)
123         break;
124       breadb(src, key, klen);
125       vlen = bgetw(src);
126       if (vlen < 0)
127         die("Corrupted dump file: value missing");
128       breadb(src, val, vlen);
129       if (!(c++ % 1024))
130         {
131           fprintf(stderr, "%d\r", c);
132           fflush(stderr);
133         }
134       if (sdbm_store(dest, key, klen, val, vlen) == 0)
135         fprintf(stderr, "sdbm_store: duplicate key\n");
136     }
137
138   bclose(src);
139   sdbm_close(dest);
140   fprintf(stderr, "Restored %d records\n", c);
141 }
142
143 static void
144 rebuild(char *sdb, char *ddb)
145 {
146   struct sdbm *src, *dest;
147   struct sdbm_options op;
148   int e, c=0;
149
150   bzero(&op, sizeof(op));
151   op.name = sdb;
152   op.cache_size = 16;
153   op.flags = 0;
154   src = sdbm_open(&op);
155   if (!src)
156     die("Source open failed: %m");
157
158   op.name = ddb;
159   e = unlink(op.name);
160   if (e < 0 && errno != ENOENT)
161     die("unlink: %m");
162   op.cache_size = cache;
163   op.flags = SDBM_CREAT | SDBM_WRITE | SDBM_FAST;
164   op.page_order = (force_page >= 0) ? (u32) force_page : src->root->page_order;
165   op.key_size = (force_key >= -1) ? force_key : src->root->key_size;
166   op.val_size = (force_val >= -1) ? force_val : src->root->val_size;
167   dest = sdbm_open(&op);
168   if (!dest)
169     die("Destination open failed");
170
171   fprintf(stderr, "Rebuilding database...\n");
172   sdbm_rewind(src);
173   for(;;)
174     {
175       byte key[65536], val[65536];
176       int klen = sizeof(key);
177       int vlen = sizeof(val);
178       e = sdbm_get_next(src, key, &klen, val, &vlen);
179       if (!e)
180         break;
181       if (e < 0)
182         fprintf(stderr, "sdbm_get_next: error %d\n", e);
183       if (!(c++ % 1024))
184         {
185           fprintf(stderr, "%d\r", c);
186           fflush(stderr);
187         }
188       if (sdbm_store(dest, key, klen, val, vlen) == 0)
189         fprintf(stderr, "sdbm_store: duplicate key\n");
190     }
191
192   sdbm_close(src);
193   sdbm_close(dest);
194   fprintf(stderr, "Copied %d records\n", c);
195 }
196
197 int
198 main(int argc, char **argv)
199 {
200   int o;
201
202   while ((o = getopt(argc, argv, "vc:k:d:p:")) >= 0)
203     switch (o)
204       {
205       case 'v':
206         verbose++;
207         break;
208       case 'c':
209         cache=atol(optarg);
210         break;
211       case 'k':
212         force_key=atol(optarg);
213         break;
214       case 'd':
215         force_val=atol(optarg);
216         break;
217       case 'p':
218         force_page=atol(optarg);
219         break;
220       default:
221       bad:
222         fprintf(stderr, "Usage: db-tool [<options>] <command> <database>\n\
223 \n\
224 Options:\n\
225 -v\t\tBe verbose\n\
226 -c<n>\t\tUse cache of <n> pages\n\
227 -d<n>\t\tSet data size to <n> (-1=variable) [restore,rebuild]\n\
228 -k<n>\t\tSet key size to <n> (-1=variable) [restore,rebuild]\n\
229 -p<n>\t\tSet page order to <n> [restore,rebuild]\n\
230 \n\
231 Commands:\n\
232 b <db> <new>\tRebuild database\n\
233 d <db> <dump>\tDump database\n\
234 r <dump> <db>\tRestore database from dump\n\
235 ");
236         return 1;
237       }
238   argc -= optind;
239   argv += optind;
240   if (argc < 1 || strlen(argv[0]) != 1)
241     goto bad;
242
243   switch (argv[0][0])
244     {
245     case 'b':
246       if (argc != 3)
247         goto bad;
248       rebuild(argv[1], argv[2]);
249       break;
250     case 'd':
251       if (argc != 3)
252         goto bad;
253       dump(argv[1], argv[2]);
254       break;
255     case 'r':
256       if (argc != 3)
257         goto bad;
258       restore(argv[1], argv[2]);
259       break;
260     default:
261       goto bad;
262     }
263   return 0;
264 }