file.c (6331B)
1 #include <stddef.h> 2 #include <string.h> 3 #include <stdio.h> 4 #include <unistd.h> 5 #include <fcntl.h> 6 7 #include <llog.h> 8 #include <hex.h> 9 10 #include "lq/crypto.h" 11 #include "lq/io.h" 12 #include "lq/store.h" 13 #include "lq/err.h" 14 #include "lq/mem.h" 15 #include "lq/query.h" 16 #include "debug.h" 17 18 static const int store_typ_file = 3; 19 20 /// \todo key and val limits proper 21 int lq_file_content_count(enum payload_e typ, LQStore *store, const char *key, size_t key_len) { 22 int r; 23 char **out; 24 char buf[LQ_STORE_KEY_MAX * 2 + 1]; 25 char pfx[1024]; 26 27 out = lq_alloc(sizeof(char**) * LQ_DIRS_MAX); 28 pfx[0] = (char)typ + 0x30; 29 b2h((const unsigned char*)key, (int)key_len, (unsigned char*)buf); 30 lq_cpy(pfx+1, buf, strlen(buf)); 31 32 r = lq_files_pfx(store->userdata, out, LQ_DIRS_MAX, pfx, key_len + 1); 33 34 lq_free(out); 35 36 return r; 37 } 38 39 int lq_file_content_get(enum payload_e typ, LQStore *store, const char *key, size_t key_len, char *value, size_t *value_len) { 40 int f; 41 size_t l; 42 size_t c; 43 char buf[LQ_STORE_KEY_MAX * 2 + 1]; 44 char path[1024]; 45 char *p; 46 47 if (store->store_typ != store_typ_file) { 48 return ERR_COMPAT; 49 } 50 51 // \todo dry 52 p = (char*)store->userdata; 53 lq_cpy(path, p, strlen(p) + 1); 54 p = path + strlen(path); 55 b2h((const unsigned char*)key, (int)key_len, (unsigned char*)buf); 56 sprintf(p, "%d%s", (char)typ, buf); 57 f = lq_open(path, O_RDONLY, S_IRUSR); 58 if (f < 0) { 59 return ERR_NOENT; 60 } 61 62 p = value; 63 l = 0; 64 while (1) { 65 c = lq_read(f, p, *value_len - l); 66 if (c == 0) { 67 break; 68 } 69 l += c; 70 if (l > *value_len) { 71 lq_close(f); 72 return ERR_OVERFLOW; 73 } 74 p += c; 75 } 76 lq_close(f); 77 78 *value_len = l; 79 80 debug_x(LLOG_DEBUG, "store.file", "get file", 2, MORGEL_TYP_STR, 0, "path", path, MORGEL_TYP_NUM, 0, "bytes", *value_len); 81 82 return ERR_OK; 83 84 } 85 86 int lq_file_content_put(enum payload_e typ, LQStore *store, const char *key, size_t *key_len, char *value, size_t value_len) { 87 size_t c; 88 size_t l; 89 char buf[LQ_STORE_KEY_MAX - 1]; 90 char path[1024]; 91 char *p; 92 int f; 93 94 if (*key_len > (LQ_STORE_KEY_MAX / 2) - 1) { 95 return ERR_OVERFLOW; 96 } 97 if (store->store_typ != store_typ_file) { 98 return ERR_COMPAT; 99 } 100 p = (char*)store->userdata; 101 lq_cpy(path, p, strlen(p) + 1); 102 p = path + strlen(path); 103 b2h((const unsigned char*)key, (int)*key_len, (unsigned char*)buf); 104 sprintf(p, "%d%s", (char)typ, (unsigned char*)buf); 105 f = lq_open(path, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR); 106 if (f < 0) { 107 return ERR_NOENT; 108 } 109 l = value_len; 110 p = value; 111 while (l > 0) { 112 c = write(f, p, l); 113 if (c < 0) { 114 lq_close(f); 115 return ERR_WRITE; 116 } 117 if (c == 0) { 118 break; 119 } 120 l -= c; 121 p += c; 122 } 123 debug_x(LLOG_DEBUG, "store.file", "put file", 2, MORGEL_TYP_STR, 0, "path", path, MORGEL_TYP_NUM, 0, "bytes", c); 124 lq_close(f); 125 return ERR_OK; 126 } 127 128 void lq_file_content_free(LQStore *store) { 129 lq_free(store->userdata); 130 lq_free(store); 131 } 132 133 /** 134 * \todo DRY with lq_files_pfx 135 * \todo prefix mismatches leak? 136 */ 137 static int query_list(const char *path, char **files, size_t files_len, const char *prefix, char prefix_len) { 138 int r; 139 int i; 140 int c; 141 size_t l; 142 143 c = 0; 144 r = lq_files(path, files, files_len); 145 for (i = 0; i < r; i++) { 146 l = strlen(*(files+i)); 147 if (l < prefix_len) { 148 lq_free(*(files+i)); 149 } 150 if (!lq_cmp(prefix, *(files+i), prefix_len)) { 151 // lq_free(*(files+c));// attempt at stopping mismatch leak. 152 *(files+c) = *(files+i); 153 c++; 154 } 155 } 156 return c; 157 } 158 159 /// \todo DRY with lq_file_count 160 LQQuery* lq_query_new(enum payload_e typ, LQStore *store, const char *key, size_t key_len) { 161 LQQuery *query; 162 //char **out; 163 char buf[LQ_STORE_KEY_MAX * 2 + 1]; 164 char pfx[1024]; 165 166 query = lq_alloc(sizeof(LQQuery)); 167 lq_zero(query, sizeof(LQQuery)); 168 query->files = lq_alloc(sizeof(char**) * LQ_DIRS_MAX); 169 pfx[0] = (char)typ + 0x30; 170 b2h((const unsigned char*)key, (int)key_len, (unsigned char*)buf); 171 lq_cpy(pfx+1, buf, strlen(buf) + 1); 172 173 key_len *= 2; 174 query->typ = typ; 175 query->files_len = query_list(store->userdata, query->files, LQ_DIRS_MAX, pfx, key_len + 1); 176 if (query->files_len == 0) { 177 return NULL; 178 } 179 query->value = lq_alloc(LQ_STORE_VAL_MAX); 180 query->key = lq_alloc(LQ_STORE_KEY_MAX); 181 query->store = store; 182 query->state = LQ_QUERY_READY; 183 184 debug_x(LLOG_DEBUG, "store.file", "query", 2, MORGEL_TYP_STR, 0, "pfx", key, MORGEL_TYP_NUM, 0, "typ", (int)typ); 185 186 return query; 187 } 188 189 int lq_query_next(LQQuery *query) { 190 int r; 191 char *p; 192 //char b[LQ_STORE_KEY_MAX]; 193 194 if (query->state & LQ_QUERY_EOF) { 195 return ERR_EOF; 196 } 197 p = *(query->files + query->files_cur) + 1; 198 query->key_len = h2b(p, (char*)query->key); 199 if (query->key_len == 0) { 200 query->state = LQ_QUERY_GONER; 201 return ERR_ENCODING; 202 } 203 query->value_len = LQ_STORE_VAL_MAX; 204 r = query->store->get(query->typ, query->store, query->key, query->key_len, query->value, &query->value_len); 205 if (r != ERR_OK) { 206 query->value_len = 0; 207 query->state = LQ_QUERY_GONER; 208 return ERR_FAIL; 209 } 210 if (++query->files_cur == query->files_len) { 211 query->state |= LQ_QUERY_EOF; 212 } 213 return ERR_OK; 214 } 215 216 int lq_query_get_val_len(LQQuery *query) { 217 if (!(query->state & LQ_QUERY_READY)) { 218 return -1; 219 } 220 return query->value_len; 221 } 222 223 char* lq_query_get_val(LQQuery *query) { 224 if (!(query->state & LQ_QUERY_READY)) { 225 return NULL; 226 } 227 return query->value; 228 } 229 230 int lq_query_get_key_len(LQQuery *query) { 231 if (!(query->state & LQ_QUERY_READY)) { 232 return -1; 233 } 234 return query->key_len; 235 } 236 237 char* lq_query_get_key(LQQuery *query) { 238 if (!(query->state & LQ_QUERY_READY)) { 239 return NULL; 240 } 241 return query->key; 242 } 243 244 void lq_query_free(LQQuery *query) { 245 char *p; 246 int i; 247 248 i = 0; 249 while(1) { 250 if (*((query->files)+i) != NULL) { 251 break; 252 } 253 lq_free(*((query->files)+i)); 254 *((query->files)+i) = NULL; 255 i++; 256 } 257 lq_free(query->files); 258 lq_free(query->key); 259 lq_free(query->value); 260 lq_free(query); 261 } 262 263 struct lq_store_t LQFileContent = { 264 .store_typ = store_typ_file, 265 .userdata = "", 266 .get = lq_file_content_get, 267 .put = lq_file_content_put, 268 .count = lq_file_content_count, 269 .free = lq_file_content_free, 270 }; 271 272 LQStore* lq_store_new(const char *spec) { 273 int l; 274 LQStore *store; 275 276 l = strlen(spec) + 1; 277 store = lq_alloc(sizeof(LQStore)); 278 lq_cpy(store, &LQFileContent, sizeof(LQFileContent)); 279 store->userdata = lq_alloc(l); 280 lq_cpy(store->userdata, spec, l); 281 return store; 282 } 283 284 void lq_store_free(LQStore *store) { 285 lq_free(store->userdata); 286 lq_free(store); 287 }