1 #include <u.h> 2 #include <libc.h> 3 #include <bio.h> 4 #include <ctype.h> 5 #include <ndb.h> 6 #include "ndbhf.h" 7 8 /* 9 * Parse a data base entry. Entries may span multiple 10 * lines. An entry starts on a left margin. All subsequent 11 * lines must be indented by white space. An entry consists 12 * of tuples of the forms: 13 * attribute-name 14 * attribute-name=value 15 * attribute-name="value with white space" 16 * 17 * The parsing returns a 2-dimensional structure. The first 18 * dimension joins all tuples. All tuples on the same line 19 * form a ring along the second dimension. 20 */ 21 22 /* 23 * parse the next entry in the file 24 */ 25 Ndbtuple* 26 ndbparse(Ndb *db) 27 { 28 char *line; 29 Ndbtuple *t; 30 Ndbtuple *first, *last; 31 int len; 32 33 first = last = 0; 34 for(;;){ 35 if((line = Brdline(&db->b, '\n')) == 0) 36 break; 37 len = Blinelen(&db->b); 38 if(line[len-1] != '\n') 39 break; 40 if(first && !ISWHITE(*line) && *line != '#'){ 41 Bseek(&db->b, -len, 1); 42 return first; 43 } 44 t = _ndbparseline(line); 45 if(t == 0) 46 continue; 47 if(first) 48 last->entry = t; 49 else 50 first = t; 51 last = t; 52 while(last->entry) 53 last = last->entry; 54 } 55 return first; 56 } 57 58 59 /* 60 * free the hash files belonging to a db 61 */ 62 static void 63 hffree(Ndb *db) 64 { 65 Ndbhf *hf, *next; 66 67 for(hf = db->hf; hf; hf = next){ 68 next = hf->next; 69 close(hf->fd); 70 free(hf); 71 } 72 db->hf = 0; 73 } 74 75 int 76 ndbreopen(Ndb *db) 77 { 78 int fd; 79 Dir d; 80 81 /* forget what we know about the open files */ 82 if(db->mtime){ 83 hffree(db); 84 close(Bfildes(&db->b)); 85 Bterm(&db->b); 86 db->mtime = 0; 87 } 88 89 /* try the open again */ 90 fd = open(db->file, OREAD); 91 if(fd < 0) 92 return -1; 93 if(dirfstat(fd, &d) < 0){ 94 close(fd); 95 return -1; 96 } 97 98 db->qid = d.qid; 99 db->mtime = d.mtime; 100 db->length = d.length; 101 Binits(&db->b, fd, OREAD, db->buf, sizeof(db->buf)); 102 return 0; 103 } 104 105 static char *deffile = "/lib/ndb/local"; 106 107 /* 108 * lookup the list of files to use in the specified database file 109 */ 110 static Ndb* 111 doopen(char *file) 112 { 113 Ndb *db; 114 115 db = (Ndb*)malloc(sizeof(Ndb)); 116 if(db == 0) 117 return 0; 118 strncpy(db->file, file, sizeof(db->file)-1); 119 db->next = 0; 120 db->hf = 0; 121 db->mtime = 0; 122 123 if(ndbreopen(db) < 0){ 124 free(db); 125 return 0; 126 } 127 128 return db; 129 } 130 Ndb* 131 ndbopen(char *file) 132 { 133 Ndb *db, *first, *last; 134 Ndbs s; 135 Ndbtuple *t, *nt; 136 137 if(file == 0) 138 file = deffile; 139 db = doopen(file); 140 if(db == 0) 141 return 0; 142 first = last = db; 143 t = ndbsearch(db, &s, "database", ""); 144 Bseek(&db->b, 0, 0); 145 if(t == 0) 146 return db; 147 for(nt = t; nt; nt = nt->entry){ 148 if(strcmp(nt->attr, "file") != 0) 149 continue; 150 if(strcmp(nt->val, file) == 0){ 151 /* default file can be reordered in the list */ 152 if(first->next == 0) 153 continue; 154 if(strcmp(first->file, file) == 0){ 155 db = first; 156 first = first->next; 157 last->next = db; 158 db->next = 0; 159 last = db; 160 } 161 continue; 162 } 163 db = doopen(nt->val); 164 if(db == 0) 165 continue; 166 last->next = db; 167 last = db; 168 } 169 return first; 170 } 171 172 void 173 ndbclose(Ndb *db) 174 { 175 Ndb *nextdb; 176 177 for(; db; db = nextdb){ 178 nextdb = db->next; 179 hffree(db); 180 close(Bfildes(&db->b)); 181 Bterm(&db->b); 182 free(db); 183 } 184 } 185