1 /*===========================================================================
2  *
3  *                            PUBLIC DOMAIN NOTICE
4  *               National Center for Biotechnology Information
5  *
6  *  This software/database is a "United States Government Work" under the
7  *  terms of the United States Copyright Act.  It was written as part of
8  *  the author's official duties as a United States Government employee and
9  *  thus cannot be copyrighted.  This software/database is freely available
10  *  to the public for use. The National Library of Medicine and the U.S.
11  *  Government have not placed any restriction on its use or reproduction.
12  *
13  *  Although all reasonable efforts have been taken to ensure the accuracy
14  *  and reliability of the software and data, the NLM and the U.S.
15  *  Government do not and cannot warrant the performance or results that
16  *  may be obtained by using this software or data. The NLM and the U.S.
17  *  Government disclaim all warranties, express or implied, including
18  *  warranties of performance, merchantability or fitness for any particular
19  *  purpose.
20  *
21  *  Please cite the author in any work or product based on this material.
22  *
23  * ===========================================================================
24  *
25  */
26 
27 #include "keyring-database.h"
28 
29 #include <vdb/database.h>
30 #include <vdb/table.h>
31 #include <vdb/manager.h>
32 #include <vdb/schema.h>
33 #include <vdb/cursor.h>
34 
35 #include "keyring-data.h"
36 
37 static const char schema_text[] =
38 "version 1; "
39 
40 " table projects : MyProjects #1 { "
41 "     extern column U32 id = .id;"
42 "     physical column U32 .id = id;"
43 
44 "     extern    column ascii name = .name;"
45 "     physical  column ascii .name = name;"
46 
47 "     extern    column ascii download_ticket = .download_ticket;"
48 "     physical  column ascii .download_ticket = download_ticket;"
49 
50 "     extern    column ascii encryption_key = .encryption_key;"
51 "     physical  column ascii .encryption_key = encryption_key;"
52 " };"
53 
54 " table objects : MyObjects #1 { "
55 "     extern    column U32 id = .id;"
56 "     physical  column U32 .id = id;"
57 
58 "     extern    column ascii name = .name;"
59 "     physical  column ascii .name = name;"
60 
61 "     extern    column ascii project = .project;"
62 "     physical  column ascii .project = project;"
63 
64 "     extern    column ascii display_name = .display_name;"
65 "     physical  column ascii .display_name = display_name;"
66 
67 "     extern    column U64   size = .size;"
68 "     physical  column U64   .size = size;"
69 
70 "     extern    column ascii checksum = .checksum;"
71 "     physical  column ascii .checksum = checksum;"
72 
73 "     extern    column ascii encryption_key = .encryption_key;"
74 "     physical  column ascii .encryption_key = encryption_key;"
75 " };"
76 
77 " table keys : MyKeys #1 { "
78 "     physical column U32   .id;"
79 "     physical column ascii .value;"
80 " };"
81 "database keyring : KEYRING #1 { "
82 "    table objects: MyObjects   #1 object_inst;"
83 "    table projects: MyProjects #1 project_inst;"
84 "    table keys : MyKeys        #1 keys_inst;"
85 "};";
86 
87 static rc_t SaveProjects( const ProjectTable* data, VDatabase* db );
88 static rc_t SaveObjects ( const ObjectTable* data,  VDatabase* db );
89 static rc_t LoadProjects( ProjectTable* data, const VDatabase* db );
90 static rc_t LoadObjects ( ObjectTable* data,  const VDatabase* db );
91 
KeyRingDatabaseSave(struct KeyRingData * self,struct KDirectory * wd,const char * path)92 rc_t KeyRingDatabaseSave ( struct KeyRingData* self, struct KDirectory* wd, const char* path )
93 {
94     rc_t rc;
95     VDBManager* vdbMgr;
96     rc = VDBManagerMakeUpdate( &vdbMgr, wd );
97     if (rc == 0)
98     {
99         VSchema* schema;
100         rc = VDBManagerMakeSchema(vdbMgr, &schema);
101         if (rc == 0)
102         {
103             rc = VSchemaParseText ( schema, "keyring_schema", schema_text, string_measure(schema_text, NULL) );
104             if (rc == 0)
105             {   /* create a database */
106                 VDatabase* db;
107                 rc = VDBManagerCreateDB(vdbMgr, & db, schema, "keyring:KEYRING", kcmCreate | kcmMD5, path);
108                 if (rc == 0)
109                 {
110                     rc_t rc2;
111                     rc = SaveProjects(&self->projects, db);
112                     if (rc == 0)
113                         rc = SaveObjects(&self->objects, db);
114                     /*TODO: SaveKeys */
115                     rc2 = VDatabaseRelease(db);
116                     if (rc == 0)
117                         rc = rc2;
118                 }
119 
120             }
121             VSchemaRelease(schema);
122         }
123         VDBManagerRelease(vdbMgr);
124     }
125 
126     return rc;
127 }
128 
KeyRingDatabaseLoad(struct KeyRingData * self,const struct KDirectory * dir,const char * path)129 rc_t KeyRingDatabaseLoad ( struct KeyRingData* self, const struct KDirectory* dir, const char* path )
130 {
131     VDBManager* innerMgr;
132     rc_t rc = VDBManagerMakeUpdate( &innerMgr, (KDirectory*)dir );
133     if (rc == 0)
134     {
135         rc_t rc2;
136         const VDatabase* db;
137         rc = VDBManagerOpenDBRead(innerMgr, & db, NULL, "%s", path);
138         if (rc == 0)
139         {
140             rc = LoadProjects(&self->projects, db);
141             if (rc == 0)
142                 rc = LoadObjects(&self->objects, db);
143             /*TODO: LoadKeys */
144             rc2 = VDatabaseRelease(db);
145             if (rc == 0)
146                 rc = rc2;
147         }
148         rc2 = VDBManagerRelease(innerMgr);
149         if (rc == 0)
150             rc = rc2;
151     }
152 
153     return rc;
154 }
155 
156 static
SaveProjects(const ProjectTable * data,VDatabase * db)157 rc_t SaveProjects( const ProjectTable* data, VDatabase* db )
158 {
159     VTable* tbl;
160     rc_t rc = VDatabaseCreateTable(db, &tbl, "project_inst", kcmCreate | kcmMD5, "PROJECTS");
161     if (rc == 0)
162     {
163         rc_t rc2;
164         VCursor *cur;
165         rc = VTableCreateCursorWrite( tbl, &cur, kcmInsert );
166         if (rc == 0)
167         {
168             uint32_t id_idx, name_idx, dl_idx, enc_idx;
169             rc = VCursorAddColumn( cur, &id_idx, "id" );
170             rc = VCursorAddColumn( cur, &name_idx, "name" );
171             rc = VCursorAddColumn( cur, &dl_idx, "download_ticket" );
172             rc = VCursorAddColumn( cur, &enc_idx, "encryption_key" );
173             if (rc == 0)
174             {
175                 rc = VCursorOpen( cur );
176                 if (rc == 0)
177                 {
178                     const Project* p = (const Project*)BSTreeFirst(data);
179                     while (rc == 0 && p != NULL)
180                     {
181                         rc = VCursorOpenRow( cur );
182 
183                         if (rc == 0) rc = VCursorWrite( cur, id_idx,    sizeof(p->id) * 8,                      &p->id,                     0, 1);
184                         if (rc == 0) rc = VCursorWrite( cur, name_idx,  StringLength(p->name) * 8,              p->name->addr,              0, 1);
185                         if (rc == 0) rc = VCursorWrite( cur, dl_idx,    StringLength(p->download_ticket) * 8,   p->download_ticket->addr,   0, 1);
186                         if (rc == 0) rc = VCursorWrite( cur, enc_idx,   StringLength(p->encryption_key) * 8,    p->encryption_key->addr,    0, 1);
187 
188                         if (rc == 0) rc = VCursorCommitRow( cur );
189                         if (rc == 0) rc = VCursorCloseRow( cur );
190 
191                         p = (const Project*)BSTNodeNext(&p->dad);
192                     }
193                     if (rc == 0)
194                         rc = VCursorCommit( cur );
195                 }
196             }
197             rc2 = VCursorRelease(cur);
198             if (rc == 0)
199                 rc = rc2;
200         }
201 
202         rc2 = VTableRelease(tbl);
203         if (rc == 0)
204             rc = rc2;
205     }
206     return rc;
207 }
208 
209 static
SaveObjects(const ObjectTable * data,VDatabase * db)210 rc_t SaveObjects ( const ObjectTable* data,  VDatabase* db )
211 {
212     VTable* tbl;
213     rc_t rc = VDatabaseCreateTable(db, &tbl, "object_inst", kcmCreate | kcmMD5, "OBJECTS");
214     if (rc == 0)
215     {
216         rc_t rc2;
217         VCursor *cur;
218         rc = VTableCreateCursorWrite( tbl, &cur, kcmInsert );
219         if (rc == 0)
220         {
221             uint32_t id_idx, name_idx, proj_idx, dname_idx, size_idx, csum_idx, enc_idx;
222             if (rc == 0) rc = VCursorAddColumn( cur, &id_idx,    "id" );
223             if (rc == 0) rc = VCursorAddColumn( cur, &name_idx,  "name" );
224             if (rc == 0) rc = VCursorAddColumn( cur, &proj_idx,    "project" );
225             if (rc == 0) rc = VCursorAddColumn( cur, &dname_idx, "display_name" );
226             if (rc == 0) rc = VCursorAddColumn( cur, &size_idx,  "size" );
227             if (rc == 0) rc = VCursorAddColumn( cur, &csum_idx,  "checksum" );
228             if (rc == 0) rc = VCursorAddColumn( cur, &enc_idx,   "encryption_key" );
229 
230             if (rc == 0)
231             {
232                 rc = VCursorOpen( cur );
233                 if (rc == 0)
234                 {
235                     const Object* obj = (const Object*)BSTreeFirst(data);
236                     while (rc == 0 && obj != NULL)
237                     {
238                         rc = VCursorOpenRow( cur );
239 
240                         if (rc == 0) rc = VCursorWrite( cur, id_idx,    sizeof(obj->id) * 8,                   &obj->id,                  0, 1);
241                         if (rc == 0) rc = VCursorWrite( cur, name_idx,  StringLength(obj->name) * 8,           obj->name->addr,           0, 1);
242                         if (rc == 0) rc = VCursorWrite( cur, proj_idx,  StringLength(obj->project) * 8,        obj->project->addr,        0, 1);
243                         if (rc == 0) rc = VCursorWrite( cur, dname_idx, StringLength(obj->display_name) * 8,   obj->display_name->addr,   0, 1);
244                         if (rc == 0) rc = VCursorWrite( cur, size_idx,  sizeof(obj->size) * 8,                 &obj->size,                0, 1);
245                         if (rc == 0) rc = VCursorWrite( cur, csum_idx,  StringLength(obj->encryption_key) * 8, obj->encryption_key->addr, 0, 1);
246                         if (rc == 0) rc = VCursorWrite( cur, enc_idx,   StringLength(obj->encryption_key) * 8, obj->encryption_key->addr, 0, 1);
247 
248                         if (rc == 0) rc = VCursorCommitRow( cur );
249                         if (rc == 0) rc = VCursorCloseRow( cur );
250 
251                         obj = (const Object*)BSTNodeNext(&obj->dad);
252                     }
253                     if (rc == 0) rc = VCursorCommit( cur );
254                 }
255             }
256             rc2 = VCursorRelease(cur);
257             if (rc == 0)
258                 rc = rc2;
259         }
260 
261         rc2 = VTableRelease(tbl);
262         if (rc == 0)
263             rc = rc2;
264     }
265     return rc;
266 }
267 
268 static size_t CursorCacheSize = 32*1024;
269 
270 static
HasData(const VTable * tbl)271 bool HasData(const VTable* tbl)
272 {
273     bool ret = false;
274     KNamelist *names;
275     if (VTableListCol(tbl, &names) == 0)
276     {
277         uint32_t n;
278         ret = KNamelistCount( names, &n ) == 0 && n > 0;
279     }
280     KNamelistRelease( names );
281     return ret;
282 }
283 
284 static
LoadProjects(ProjectTable * data,const VDatabase * db)285 rc_t LoadProjects( ProjectTable* data, const VDatabase* db )
286 {
287     const VTable* tbl;
288     rc_t rc = VDatabaseOpenTableRead(db, &tbl, "PROJECTS");
289     if (rc == 0)
290     {
291         rc_t rc2;
292         const VCursor *cur;
293 
294         rc = VTableCreateCachedCursorRead( tbl, &cur, CursorCacheSize );
295         if (rc == 0)
296         {
297             uint32_t id_idx, name_idx, dl_idx, enc_idx;
298             rc = VCursorAddColumn( cur, &id_idx,    "id" );
299             if (rc == 0) rc = VCursorAddColumn( cur, &name_idx,  "name" );
300             if (rc == 0) rc = VCursorAddColumn( cur, &dl_idx,    "download_ticket" );
301             if (rc == 0) rc = VCursorAddColumn( cur, &enc_idx,   "encryption_key" );
302             if (rc == 0 && HasData(tbl))
303             {
304                 rc = VCursorOpen( cur );
305                 if (rc == 0)
306                 {
307                     int64_t  first;
308                     uint64_t count;
309                     rc = VCursorIdRange( cur, 0, &first, &count );
310                     if (rc == 0)
311                     {
312                         uint64_t i;
313                         for (i=0; i < count; ++i)
314                         {
315                             const void* ptr;
316                             uint32_t elem_count;
317                             uint32_t id;
318                             String name;
319                             String download_ticket;
320                             String encryption_key;
321 
322                             rc = VCursorSetRowId(cur, first + i);
323                             if (rc == 0) rc = VCursorOpenRow( cur );
324 
325                             if (rc == 0) rc = VCursorCellData( cur, id_idx, NULL, &ptr, NULL, NULL);
326                             if (rc == 0) id = *(uint32_t*)ptr;
327                             if (rc == 0) rc = VCursorCellData( cur, name_idx, NULL, &ptr, NULL, &elem_count);
328                             if (rc == 0) StringInit(&name, (const char*)ptr, elem_count, elem_count);
329                             if (rc == 0) rc = VCursorCellData( cur, dl_idx, NULL, &ptr, NULL, &elem_count);
330                             if (rc == 0) StringInit(&download_ticket, (const char*)ptr, elem_count, elem_count);
331                             if (rc == 0) rc = VCursorCellData( cur, enc_idx, NULL, &ptr, NULL, &elem_count);
332                             if (rc == 0) StringInit(&encryption_key, (const char*)ptr, elem_count, elem_count);
333 
334                             if (rc == 0) rc = KeyRingDataInsertProject(data, id, &name, &download_ticket, &encryption_key);
335                             if (rc == 0) rc = VCursorCloseRow( cur );
336                             if (rc != 0)
337                                 break;
338                         }
339                     }
340                 }
341             }
342             rc2 = VCursorRelease(cur);
343             if (rc == 0)
344                 rc = rc2;
345         }
346 
347         rc2 = VTableRelease(tbl);
348         if (rc == 0)
349             rc = rc2;
350     }
351     return rc;
352 }
353 
354 static
LoadObjects(ObjectTable * data,const VDatabase * db)355 rc_t LoadObjects ( ObjectTable* data,  const VDatabase* db )
356 {
357     const VTable* tbl;
358     rc_t rc = VDatabaseOpenTableRead(db, &tbl, "OBJECTS");
359     if (rc == 0)
360     {
361         rc_t rc2;
362         const VCursor *cur;
363 
364         rc = VTableCreateCachedCursorRead( tbl, &cur, CursorCacheSize );
365         if (rc == 0)
366         {
367             uint32_t id_idx, name_idx, proj_idx, dname_idx, size_idx, csum_idx, enc_idx;
368             if (rc == 0) rc = VCursorAddColumn( cur, &id_idx,    "id" );
369             if (rc == 0) rc = VCursorAddColumn( cur, &name_idx,  "name" );
370             if (rc == 0) rc = VCursorAddColumn( cur, &proj_idx,    "project" );
371             if (rc == 0) rc = VCursorAddColumn( cur, &dname_idx, "display_name" );
372             if (rc == 0) rc = VCursorAddColumn( cur, &size_idx,  "size" );
373             if (rc == 0) rc = VCursorAddColumn( cur, &csum_idx,  "checksum" );
374             if (rc == 0) rc = VCursorAddColumn( cur, &enc_idx,   "encryption_key" );
375             if (rc == 0 && HasData(tbl))
376             {
377                 rc = VCursorOpen( cur );
378                 if (rc == 0)
379                 {
380                     int64_t  first;
381                     uint64_t count;
382                     rc = VCursorIdRange( cur, 0, &first, &count );
383                     if (rc == 0)
384                     {
385                         uint64_t i;
386                         for (i=0; i < count; ++i)
387                         {
388                             const void* ptr;
389                             uint32_t elem_count;
390                             uint32_t id;
391                             String name;
392                             String project;
393                             String display_name;
394                             uint64_t size;
395                             String checksum;
396                             String encryption_key;
397 
398                             rc = VCursorSetRowId(cur, first + i);
399                             if (rc == 0) rc = VCursorOpenRow( cur );
400 
401                             if (rc == 0) rc = VCursorCellData( cur, id_idx, NULL, &ptr, NULL, NULL);
402                             if (rc == 0) id = *(uint32_t*)ptr;
403 
404                             if (rc == 0) rc = VCursorCellData( cur, name_idx, NULL, &ptr, NULL, &elem_count);
405                             if (rc == 0) StringInit(&name, (const char*)ptr, elem_count, elem_count);
406 
407                             if (rc == 0) rc = VCursorCellData( cur, proj_idx, NULL, &ptr, NULL, &elem_count);
408                             if (rc == 0) StringInit(&project, (const char*)ptr, elem_count, elem_count);
409 
410                             if (rc == 0) rc = VCursorCellData( cur, dname_idx, NULL, &ptr, NULL, &elem_count);
411                             if (rc == 0) StringInit(&display_name, (const char*)ptr, elem_count, elem_count);
412 
413                             if (rc == 0) rc = VCursorCellData( cur, size_idx, NULL, &ptr, NULL, NULL);
414                             if (rc == 0) size = *(uint32_t*)ptr;
415 
416                             if (rc == 0) rc = VCursorCellData( cur, enc_idx, NULL, &ptr, NULL, &elem_count);
417                             if (rc == 0) StringInit(&encryption_key, (const char*)ptr, elem_count, elem_count);
418 
419                             if (rc == 0) rc = VCursorCellData( cur, csum_idx, NULL, &ptr, NULL, &elem_count);
420                             if (rc == 0) StringInit(&checksum, (const char*)ptr, elem_count, elem_count);
421 
422                             if (rc == 0) rc = KeyRingDataInsertObject(data, id, &name, &project, &display_name, size, &checksum, &encryption_key);
423                             if (rc == 0) rc = VCursorCloseRow( cur );
424                             if (rc != 0)
425                                 break;
426                         }
427                     }
428                 }
429             }
430             rc2 = VCursorRelease(cur);
431             if (rc == 0)
432                 rc = rc2;
433         }
434 
435         rc2 = VTableRelease(tbl);
436         if (rc == 0)
437             rc = rc2;
438     }
439     return rc;
440 }
441 
442