ndbopen.c (2981B)
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 static Ndb* doopen(char*, char*); 9 static void hffree(Ndb*); 10 11 static char *deffile = "#9/ndb/local"; 12 13 /* 14 * the database entry in 'file' indicates the list of files 15 * that makeup the database. Open each one and search in 16 * the same order. 17 */ 18 Ndb* 19 ndbopen(char *file) 20 { 21 Ndb *db, *first, *last; 22 Ndbs s; 23 Ndbtuple *t, *nt; 24 25 if(file == 0) 26 file = unsharp(deffile); 27 db = doopen(file, nil); 28 if(db == 0) 29 return 0; 30 first = last = db; 31 t = ndbsearch(db, &s, "database", ""); 32 Bseek(&db->b, 0, 0); 33 if(t == 0) 34 return db; 35 for(nt = t; nt; nt = nt->entry){ 36 if(strcmp(nt->attr, "file") != 0) 37 continue; 38 if(strcmp(nt->val, file) == 0){ 39 /* default file can be reordered in the list */ 40 if(first->next == 0) 41 continue; 42 if(strcmp(first->file, file) == 0){ 43 db = first; 44 first = first->next; 45 last->next = db; 46 db->next = 0; 47 last = db; 48 } 49 continue; 50 } 51 db = doopen(nt->val, file); 52 if(db == 0) 53 continue; 54 last->next = db; 55 last = db; 56 } 57 ndbfree(t); 58 return first; 59 } 60 61 /* 62 * open a single file 63 */ 64 static Ndb* 65 doopen(char *file, char *rel) 66 { 67 char *p; 68 Ndb *db; 69 70 db = (Ndb*)malloc(sizeof(Ndb)); 71 if(db == 0) 72 return 0; 73 74 memset(db, 0, sizeof(Ndb)); 75 /* 76 * Rooted paths are taken as is. 77 * Unrooted paths are taken relative to db we opened. 78 */ 79 if(file[0]!='/' && rel && (p=strrchr(rel, '/'))!=nil) 80 snprint(db->file, sizeof(db->file), "%.*s/%s", 81 utfnlen(rel, p-rel), rel, file); 82 else 83 strncpy(db->file, file, sizeof(db->file)-1); 84 85 if(ndbreopen(db) < 0){ 86 free(db); 87 return 0; 88 } 89 90 return db; 91 } 92 93 /* 94 * dump any cached information, forget the hash tables, and reopen a single file 95 */ 96 int 97 ndbreopen(Ndb *db) 98 { 99 int fd; 100 Dir *d; 101 102 /* forget what we know about the open files */ 103 if(db->mtime){ 104 _ndbcacheflush(db); 105 hffree(db); 106 close(Bfildes(&db->b)); 107 Bterm(&db->b); 108 db->mtime = 0; 109 } 110 111 /* try the open again */ 112 fd = open(db->file, OREAD); 113 if(fd < 0) 114 return -1; 115 d = dirfstat(fd); 116 if(d == nil){ 117 close(fd); 118 return -1; 119 } 120 121 db->qid = d->qid; 122 db->mtime = d->mtime; 123 db->length = d->length; 124 Binit(&db->b, fd, OREAD); 125 free(d); 126 return 0; 127 } 128 129 /* 130 * close the database files 131 */ 132 void 133 ndbclose(Ndb *db) 134 { 135 Ndb *nextdb; 136 137 for(; db; db = nextdb){ 138 nextdb = db->next; 139 _ndbcacheflush(db); 140 hffree(db); 141 close(Bfildes(&db->b)); 142 Bterm(&db->b); 143 free(db); 144 } 145 } 146 147 /* 148 * free the hash files belonging to a db 149 */ 150 static void 151 hffree(Ndb *db) 152 { 153 Ndbhf *hf, *next; 154 155 for(hf = db->hf; hf; hf = next){ 156 next = hf->next; 157 close(hf->fd); 158 free(hf); 159 } 160 db->hf = 0; 161 } 162 163 /* 164 * return true if any part of the database has changed 165 */ 166 int 167 ndbchanged(Ndb *db) 168 { 169 Ndb *ndb; 170 Dir *d; 171 172 for(ndb = db; ndb != nil; ndb = ndb->next){ 173 d = dirfstat(Bfildes(&db->b)); 174 if(d == nil) 175 continue; 176 if(ndb->qid.path != d->qid.path 177 || ndb->qid.vers != d->qid.vers){ 178 free(d); 179 return 1; 180 } 181 free(d); 182 } 183 return 0; 184 }