dav/pwd.c

changeset 747
efbd59642577
parent 731
e0358fa1a3b1
child 789
378b5ab86f77
equal deleted inserted replaced
746:a569148841ff 747:efbd59642577
26 * POSSIBILITY OF SUCH DAMAGE. 26 * POSSIBILITY OF SUCH DAMAGE.
27 */ 27 */
28 28
29 #include <stdio.h> 29 #include <stdio.h>
30 #include <stdlib.h> 30 #include <stdlib.h>
31 #include <string.h>
31 32
32 #include "pwd.h" 33 #include "pwd.h"
33 34
34 #include <ucx/buffer.h> 35 #include <cx/buffer.h>
35 #include <ucx/utils.h> 36 #include <cx/utils.h>
37 #include <cx/hash_map.h>
36 38
37 #ifdef _WIN32 39 #ifdef _WIN32
38 #include <winsock.h> 40 #include <winsock.h>
39 #else 41 #else
40 #include <netinet/in.h> 42 #include <netinet/in.h>
44 FILE *in = fopen(file, "r"); 46 FILE *in = fopen(file, "r");
45 if(!in) { 47 if(!in) {
46 return NULL; 48 return NULL;
47 } 49 }
48 50
49 UcxBuffer *buf = ucx_buffer_new(NULL, 2048, UCX_BUFFER_AUTOEXTEND); 51 CxBuffer *buf = cxBufferCreate(NULL, 2048, cxDefaultAllocator, CX_BUFFER_FREE_CONTENTS|CX_BUFFER_AUTO_EXTEND);
50 ucx_stream_copy(in, buf, (read_func)fread, (write_func)ucx_buffer_write); 52 cx_stream_copy(in, buf, (cx_read_func)fread, (cx_write_func)cxBufferWrite);
51 fclose(in); 53 fclose(in);
52 54
53 if(buf->size < PWDS_HEADER_SIZE || buf->space[0] != PWDS_MAGIC_CHAR) { 55 if(buf->size < PWDS_HEADER_SIZE || buf->space[0] != PWDS_MAGIC_CHAR) {
54 ucx_buffer_free(buf); 56 cxBufferFree(buf);
55 return NULL; 57 return NULL;
56 } 58 }
57 59
58 PwdStore *p = malloc(sizeof(PwdStore)); 60 PwdStore *p = malloc(sizeof(PwdStore));
59 p->ids = ucx_map_new(16); 61 p->ids = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, 16);
60 p->locations = NULL; 62 p->locations = cxLinkedListCreateSimple(CX_STORE_POINTERS);
61 p->noloc = NULL; 63 p->noloc = cxLinkedListCreateSimple(CX_STORE_POINTERS);
62 p->index = ucx_map_new(16); 64 p->index = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, 16);
63 p->content = buf; 65 p->content = buf;
64 p->key = NULL; 66 p->key = NULL;
65 p->unlock_cmd = NULL; 67 p->unlock_cmd = NULL;
66 p->lock_cmd = NULL; 68 p->lock_cmd = NULL;
67 p->encoffset = PWDS_HEADER_SIZE; 69 p->encoffset = PWDS_HEADER_SIZE;
75 return p; 77 return p;
76 } 78 }
77 79
78 PwdStore* pwdstore_new(void) { 80 PwdStore* pwdstore_new(void) {
79 PwdStore *p = calloc(1, sizeof(PwdStore)); 81 PwdStore *p = calloc(1, sizeof(PwdStore));
80 p->ids = ucx_map_new(16); 82 p->ids = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, 16);
81 p->locations = NULL; 83 p->locations = cxLinkedListCreateSimple(CX_STORE_POINTERS);
82 p->noloc = NULL; 84 p->noloc = cxLinkedListCreateSimple(CX_STORE_POINTERS);
83 p->index = ucx_map_new(16); 85 p->index = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, 16);
84 p->content = ucx_buffer_new(NULL, PWDS_HEADER_SIZE, UCX_BUFFER_AUTOEXTEND); 86 p->content = cxBufferCreate(NULL, PWDS_HEADER_SIZE, cxDefaultAllocator, CX_BUFFER_FREE_CONTENTS|CX_BUFFER_AUTO_EXTEND);
85 PWDS_MAGIC(p) = PWDS_MAGIC_CHAR; 87 PWDS_MAGIC(p) = PWDS_MAGIC_CHAR;
86 PWDS_VERSION(p) = 1; 88 PWDS_VERSION(p) = 1;
87 PWDS_ENC(p) = DAV_KEY_AES256; 89 PWDS_ENC(p) = DAV_KEY_AES256;
88 PWDS_PWFUNC(p) = DAV_PWFUNC_PBKDF2_SHA256; 90 PWDS_PWFUNC(p) = DAV_PWFUNC_PBKDF2_SHA256;
89 dav_rand_bytes((unsigned char*)p->content->space+4, 16); 91 dav_rand_bytes((unsigned char*)p->content->space+4, 16);
90 p->isdecrypted = 1; 92 p->isdecrypted = 1;
91 p->encoffset = PWDS_HEADER_SIZE; 93 p->encoffset = PWDS_HEADER_SIZE;
92 return p; 94 return p;
93 } 95 }
94 96
95 static int readval(UcxBuffer *in, char **val, int allowzero) { 97 static int readval(CxBuffer *in, char **val, int allowzero) {
96 // value = length string 98 // value = length string
97 // length = uint32 99 // length = uint32
98 // string = bytes 100 // string = bytes
99 101
100 *val = NULL; 102 *val = NULL;
101 103
102 // get length 104 // get length
103 uint32_t length = 0; 105 uint32_t length = 0;
104 if(ucx_buffer_read(&length, 1, sizeof(uint32_t), in) != sizeof(uint32_t)) { 106 if(cxBufferRead(&length, 1, sizeof(uint32_t), in) != sizeof(uint32_t)) {
105 return 0; 107 return 0;
106 } 108 }
107 length = ntohl(length); // convert from BE to host byte order 109 length = ntohl(length); // convert from BE to host byte order
108 if(length == 0) { 110 if(length == 0) {
109 if(allowzero) { 111 if(allowzero) {
117 } 119 }
118 120
119 // get value 121 // get value
120 char *value = malloc(length + 1); 122 char *value = malloc(length + 1);
121 value[length] = 0; 123 value[length] = 0;
122 if(ucx_buffer_read(value, 1, length, in) != length) { 124 if(cxBufferRead(value, 1, length, in) != length) {
123 free(value); 125 free(value);
124 return 0; 126 return 0;
125 } 127 }
126 128
127 *val = value; 129 *val = value;
128 return 1; 130 return 1;
129 } 131 }
130 132
131 static int read_indexentry(PwdStore *p, UcxBuffer *in) { 133 static int read_indexentry(PwdStore *p, CxBuffer *in) {
132 // read type of index element 134 // read type of index element
133 int type = ucx_buffer_getc(in); 135 int type = cxBufferGet(in);
134 if(type == EOF || type != 0) { 136 if(type == EOF || type != 0) {
135 // only type 0 supported yet 137 // only type 0 supported yet
136 return 0; 138 return 0;
137 } 139 }
138 140
139 char *id = NULL; 141 char *id = NULL;
140 UcxList *locations = NULL; 142 CxList *locations = cxLinkedListCreateSimple(CX_STORE_POINTERS);
143 locations->simple_destructor = free;
141 144
142 // get id (required) 145 // get id (required)
143 int ret = 0; 146 int ret = 0;
144 if(readval(in, &id, FALSE)) { 147 if(readval(in, &id, FALSE)) {
145 ret = 1; 148 ret = 1;
147 char *location = NULL; 150 char *location = NULL;
148 while((ret = readval(in, &location, TRUE)) == 1) { 151 while((ret = readval(in, &location, TRUE)) == 1) {
149 if(!location) { 152 if(!location) {
150 break; 153 break;
151 } 154 }
152 locations = ucx_list_append(locations, location); 155 cxListAdd(locations, location);
153 } 156 }
154 } 157 }
155 158
156 if(ret) { 159 if(ret) {
157 pwdstore_put_index(p, id, locations); 160 pwdstore_put_index(p, id, locations);
158 } else { 161 } else {
159 if(id) free(id); 162 if(id) free(id);
160 ucx_list_free_content(locations, free); 163 cxListDestroy(locations);
161 } 164 }
162 165
163 return ret; 166 return ret;
164 } 167 }
165 168
166 static int read_pwdentry(PwdStore *p, UcxBuffer *in) { 169 static int read_pwdentry(PwdStore *p, CxBuffer *in) {
167 int type = ucx_buffer_getc(in); 170 int type = cxBufferGet(in);
168 if(type == EOF || type != 0) { 171 if(type == EOF || type != 0) {
169 // only type 0 supported yet 172 // only type 0 supported yet
170 return 0; 173 return 0;
171 } 174 }
172 175
194 } 197 }
195 198
196 static int remove_list_entries(PwdStore *s, const char *id) { 199 static int remove_list_entries(PwdStore *s, const char *id) {
197 int ret = 0; 200 int ret = 0;
198 201
199 UcxList *loc_entry = NULL; 202 CxList *loc_entry = NULL;
200 UcxList *noloc_entry = NULL; 203 CxList *noloc_entry = NULL;
201 UCX_FOREACH(elm, s->locations) { 204
202 PwdIndexEntry *ie = elm->data; 205 CxMutIterator i = cxListMutIterator(s->locations);
206 cx_foreach(PwdIndexEntry*, ie, i) {
203 if(!strcmp(ie->id, id)) { 207 if(!strcmp(ie->id, id)) {
204 loc_entry = elm; 208 cxIteratorFlagRemoval(i);
205 ret = 1; 209 // TODO: break loop
206 break; 210 }
207 } 211 }
208 } 212 i = cxListMutIterator(s->noloc);
209 UCX_FOREACH(elm, s->noloc) { 213 cx_foreach(PwdIndexEntry*, ie, i) {
210 PwdIndexEntry *ie = elm->data;
211 if(!strcmp(ie->id, id)) { 214 if(!strcmp(ie->id, id)) {
212 noloc_entry = elm; 215 cxIteratorFlagRemoval(i);
213 ret = 1; 216 // TODO: break loop
214 break; 217 }
215 }
216 }
217
218 if(loc_entry) {
219 s->locations = ucx_list_remove(s->locations, loc_entry);
220 }
221 if(noloc_entry) {
222 s->noloc = ucx_list_remove(s->noloc, noloc_entry);
223 } 218 }
224 219
225 return ret; 220 return ret;
226 } 221 }
227 222
228 void pwdstore_remove_entry(PwdStore *s, const char *id) { 223 void pwdstore_remove_entry(PwdStore *s, const char *id) {
229 while(remove_list_entries(s, id)) {} 224 while(remove_list_entries(s, id)) {}
230 225
231 PwdIndexEntry *i = ucx_map_cstr_remove(s->index, id); 226 CxHashKey key = cx_hash_key_str(id);
232 PwdEntry *e = ucx_map_cstr_remove(s->ids, id); 227 PwdIndexEntry *i = cxMapRemoveAndGet(s->index, key);
228 PwdEntry *e = cxMapRemoveAndGet(s->ids, key);
233 229
234 if(i) { 230 if(i) {
235 ucx_list_free_content(i->locations, free); 231 cxListDestroy(i->locations);
236 ucx_list_free(i->locations);
237 free(i->id); 232 free(i->id);
238 free(i); 233 free(i);
239 } 234 }
240 if(e) { 235 if(e) {
241 free(e->id); 236 free(e->id);
251 // set the position to the last 4 bytes of the header 246 // set the position to the last 4 bytes of the header
252 // for reading index length 247 // for reading index length
253 s->content->pos = PWDS_HEADER_SIZE - sizeof(uint32_t); 248 s->content->pos = PWDS_HEADER_SIZE - sizeof(uint32_t);
254 249
255 // read indexlen and convert to host byte order 250 // read indexlen and convert to host byte order
256 if(ucx_buffer_read(&netindexlen, 1, sizeof(uint32_t), s->content) != sizeof(uint32_t)) { 251 if(cxBufferRead(&netindexlen, 1, sizeof(uint32_t), s->content) != sizeof(uint32_t)) {
257 return 1; 252 return 1;
258 } 253 }
259 uint32_t indexlen = ntohl(netindexlen); 254 uint32_t indexlen = ntohl(netindexlen);
260 255
261 // integer overflow check 256 // integer overflow check
267 } 262 }
268 // encrypted content starts after the index content 263 // encrypted content starts after the index content
269 s->encoffset = PWDS_HEADER_SIZE + indexlen; 264 s->encoffset = PWDS_HEADER_SIZE + indexlen;
270 265
271 // the index starts after the header 266 // the index starts after the header
272 UcxBuffer *index = ucx_buffer_new(s->content->space+PWDS_HEADER_SIZE, indexlen, 0); 267 CxBuffer *index = cxBufferCreate(s->content->space+PWDS_HEADER_SIZE, indexlen, cxDefaultAllocator, 0);
273 index->size = indexlen; 268 index->size = indexlen;
274 269
275 // read index 270 // read index
276 while(read_indexentry(s, index)) {} 271 while(read_indexentry(s, index)) {}
277 272
278 // free index buffer structure (not the content) 273 // free index buffer structure (not the content)
279 ucx_buffer_free(index); 274 cxBufferFree(index);
280 275
281 return 0; 276 return 0;
282 } 277 }
283 278
284 int pwdstore_decrypt(PwdStore *p) { 279 int pwdstore_decrypt(PwdStore *p) {
289 return 0; 284 return 0;
290 } 285 }
291 286
292 // decrypt contet 287 // decrypt contet
293 size_t encsz = p->content->size - p->encoffset; 288 size_t encsz = p->content->size - p->encoffset;
294 UcxBuffer *enc = ucx_buffer_new(p->content->space + p->encoffset, encsz, 0); 289 CxBuffer *enc = cxBufferCreate(p->content->space + p->encoffset, encsz, cxDefaultAllocator, 0);
295 enc->size = encsz; 290 enc->size = encsz;
296 enc->size = p->content->size - p->encoffset; 291 enc->size = p->content->size - p->encoffset;
297 UcxBuffer *content = aes_decrypt_buffer(enc, p->key); 292 CxBuffer *content = aes_decrypt_buffer(enc, p->key);
298 ucx_buffer_free(enc); 293 cxBufferFree(enc);
299 if(!content) { 294 if(!content) {
300 return 1; 295 return 1;
301 } 296 }
302 297
303 while(read_pwdentry(p, content)) {} 298 while(read_pwdentry(p, content)) {}
304 299
305 ucx_buffer_free(content); 300 cxBufferFree(content);
306 301
307 return 0; 302 return 0;
308 } 303 }
309 304
310 int pwdstore_setpassword(PwdStore *p, const char *password) { 305 int pwdstore_setpassword(PwdStore *p, const char *password) {
333 if(e->password) free(e->password); 328 if(e->password) free(e->password);
334 free(e); 329 free(e);
335 } 330 }
336 331
337 void pwdstore_free(PwdStore* p) { 332 void pwdstore_free(PwdStore* p) {
338 ucx_map_free_content(p->ids, (ucx_destructor)pwdstore_free_entry); 333 p->ids->simple_destructor = (cx_destructor_func)pwdstore_free_entry;
339 ucx_map_free(p->ids); 334 cxMapDestroy(p->ids);
340 335
341 ucx_list_free(p->locations); 336 cxListDestroy(p->locations);
342 337
343 if(p->content) { 338 if(p->content) {
344 ucx_buffer_free(p->content); 339 cxBufferFree(p->content);
345 } 340 }
346 341
347 free(p); 342 free(p);
348 } 343 }
349 344
350 int pwdstore_has_id(PwdStore *s, const char *id) { 345 int pwdstore_has_id(PwdStore *s, const char *id) {
351 return ucx_map_cstr_get(s->index, id) ? 1 : 0; 346 return cxMapGet(s->index, cx_hash_key_str(id)) ? 1 : 0;
352 } 347 }
353 348
354 PwdEntry* pwdstore_get(PwdStore *p, const char *id) { 349 PwdEntry* pwdstore_get(PwdStore *p, const char *id) {
355 PwdEntry *e = ucx_map_cstr_get(p->ids, id); 350 PwdEntry *e = cxMapGet(p->ids, cx_hash_key_str(id));
356 if(e && e->user && e->password) { 351 if(e && e->user && e->password) {
357 return e; 352 return e;
358 } else { 353 } else {
359 return NULL; 354 return NULL;
360 } 355 }
363 void pwdstore_put(PwdStore *p, const char *id, const char *username, const char *password) { 358 void pwdstore_put(PwdStore *p, const char *id, const char *username, const char *password) {
364 PwdEntry *entry = malloc(sizeof(PwdEntry)); 359 PwdEntry *entry = malloc(sizeof(PwdEntry));
365 entry->id = strdup(id); 360 entry->id = strdup(id);
366 entry->user = strdup(username); 361 entry->user = strdup(username);
367 entry->password = strdup(password); 362 entry->password = strdup(password);
368 ucx_map_cstr_put(p->ids, id, entry); 363 cxMapPut(p->ids, cx_hash_key_str(id), entry);
369 } 364 }
370 365
371 void pwdstore_put_index(PwdStore *p, char *id, UcxList *locations) { 366 void pwdstore_put_index(PwdStore *p, char *id, CxList *locations) {
372 PwdIndexEntry *e = ucx_map_cstr_get(p->index, id); 367 PwdIndexEntry *e = cxMapGet(p->index, cx_hash_key_str(id));
373 if(e) { 368 if(e) {
374 return; 369 return;
375 } 370 }
376 PwdIndexEntry *newentry = malloc(sizeof(PwdIndexEntry)); 371 PwdIndexEntry *newentry = malloc(sizeof(PwdIndexEntry));
377 newentry->id = id; 372 newentry->id = id;
378 if(locations) { 373 if(locations) {
379 newentry->locations = locations; 374 newentry->locations = locations;
380 p->locations = ucx_list_append(p->locations, newentry); 375 cxListAdd(p->locations, newentry);
381 } else { 376 } else {
382 newentry->locations = NULL; 377 newentry->locations = NULL;
383 p->noloc = ucx_list_append(p->noloc, newentry); 378 cxListAdd(p->noloc, newentry);
384 } 379 }
385 ucx_map_cstr_put(p->index, id, newentry); 380 cxMapPut(p->index, cx_hash_key_str(id), newentry);
386 } 381 }
387 382
388 void write_index_entry(UcxBuffer *out, PwdIndexEntry *e) { 383 void write_index_entry(CxBuffer *out, PwdIndexEntry *e) {
389 uint32_t idlen = strlen(e->id); 384 uint32_t idlen = strlen(e->id);
390 uint32_t netidlen = htonl(idlen); 385 uint32_t netidlen = htonl(idlen);
391 386
392 ucx_buffer_putc(out, 0); // type 387 cxBufferPut(out, 0); // type
393 388
394 ucx_buffer_write(&netidlen, 1, sizeof(uint32_t), out); 389 cxBufferWrite(&netidlen, 1, sizeof(uint32_t), out);
395 ucx_buffer_write(e->id, 1, idlen, out); 390 cxBufferWrite(e->id, 1, idlen, out);
396 391
397 UCX_FOREACH(elm, e->locations) { 392 CxIterator i = cxListIterator(e->locations);
398 char *location = elm->data; 393 cx_foreach(char *, location, i) {
399 uint32_t locationlen = strlen(location); 394 uint32_t locationlen = strlen(location);
400 uint32_t netlocationlen = htonl(locationlen); 395 uint32_t netlocationlen = htonl(locationlen);
401 396
402 ucx_buffer_write(&netlocationlen, 1, sizeof(uint32_t), out); 397 cxBufferWrite(&netlocationlen, 1, sizeof(uint32_t), out);
403 ucx_buffer_write(location, 1, locationlen, out); 398 cxBufferWrite(location, 1, locationlen, out);
404 } 399 }
405 400
406 uint32_t terminate = 0; 401 uint32_t terminate = 0;
407 ucx_buffer_write(&terminate, 1, sizeof(uint32_t), out); 402 cxBufferWrite(&terminate, 1, sizeof(uint32_t), out);
408 } 403 }
409 404
410 int pwdstore_store(PwdStore *p, const char *file) { 405 int pwdstore_store(PwdStore *p, const char *file) {
411 if(!p->key) { 406 if(!p->key) {
412 return 1; 407 return 1;
413 } 408 }
414 409
415 UcxBuffer *index = ucx_buffer_new(NULL, 2048, UCX_BUFFER_AUTOEXTEND); 410 CxBuffer *index = cxBufferCreate(NULL, 2048, cxDefaultAllocator, CX_BUFFER_FREE_CONTENTS|CX_BUFFER_AUTO_EXTEND);
416 UcxBuffer *content = ucx_buffer_new(NULL, 2048, UCX_BUFFER_AUTOEXTEND); 411 CxBuffer *content = cxBufferCreate(NULL, 2048, cxDefaultAllocator, CX_BUFFER_FREE_CONTENTS|CX_BUFFER_AUTO_EXTEND);
417 412
418 // create index 413 // create index
419 UCX_FOREACH(elm, p->noloc) { 414 CxIterator i = cxListIterator(p->noloc);
420 PwdIndexEntry *e = elm->data; 415 cx_foreach(PwdIndexEntry*, e, i) {
421 write_index_entry(index, e); 416 write_index_entry(index, e);
422 } 417 }
423 UCX_FOREACH(elm, p->locations) { 418 i = cxListIterator(p->locations);
424 PwdIndexEntry *e = elm->data; 419 cx_foreach(PwdIndexEntry*, e, i) {
425 write_index_entry(index, e); 420 write_index_entry(index, e);
426 } 421 }
427 422
428 UcxMapIterator i = ucx_map_iterator(p->ids); 423 i = cxMapIteratorValues(p->ids);
429 PwdEntry *value; 424 cx_foreach(PwdEntry*, value, i) {
430 UCX_MAP_FOREACH(key, value, i) {
431 if(!value->id || !value->user || !value->password) { 425 if(!value->id || !value->user || !value->password) {
432 continue; 426 continue;
433 } 427 }
434 428
435 uint32_t idlen = strlen(value->id); 429 uint32_t idlen = strlen(value->id);
438 uint32_t netidlen = htonl(idlen); 432 uint32_t netidlen = htonl(idlen);
439 uint32_t netulen = htonl(ulen); 433 uint32_t netulen = htonl(ulen);
440 uint32_t netplen = htonl(plen); 434 uint32_t netplen = htonl(plen);
441 435
442 // content buffer 436 // content buffer
443 ucx_buffer_putc(content, 0); // type 437 cxBufferPut(content, 0); // type
444 438
445 ucx_buffer_write(&netidlen, 1, sizeof(uint32_t), content); 439 cxBufferWrite(&netidlen, 1, sizeof(uint32_t), content);
446 ucx_buffer_write(value->id, 1, idlen, content); 440 cxBufferWrite(value->id, 1, idlen, content);
447 ucx_buffer_write(&netulen, 1, sizeof(uint32_t), content); 441 cxBufferWrite(&netulen, 1, sizeof(uint32_t), content);
448 ucx_buffer_write(value->user, 1, ulen, content); 442 cxBufferWrite(value->user, 1, ulen, content);
449 ucx_buffer_write(&netplen, 1, sizeof(uint32_t), content); 443 cxBufferWrite(&netplen, 1, sizeof(uint32_t), content);
450 ucx_buffer_write(value->password, 1, plen, content); 444 cxBufferWrite(value->password, 1, plen, content);
451 } 445 }
452 446
453 content->pos = 0; 447 content->pos = 0;
454 UcxBuffer *enc = aes_encrypt_buffer(content, p->key); 448 CxBuffer *enc = aes_encrypt_buffer(content, p->key);
455 449
456 p->content->pos = PWDS_HEADER_SIZE - sizeof(uint32_t); 450 p->content->pos = PWDS_HEADER_SIZE - sizeof(uint32_t);
457 p->content->size = PWDS_HEADER_SIZE; 451 p->content->size = PWDS_HEADER_SIZE;
458 452
459 // add index after header 453 // add index after header
460 uint32_t netindexlen = htonl((uint32_t)index->size); 454 uint32_t netindexlen = htonl((uint32_t)index->size);
461 ucx_buffer_write(&netindexlen, 1, sizeof(uint32_t), p->content); 455 cxBufferWrite(&netindexlen, 1, sizeof(uint32_t), p->content);
462 ucx_buffer_write(index->space, 1, index->size, p->content); 456 cxBufferWrite(index->space, 1, index->size, p->content);
463 457
464 // add encrypted buffer 458 // add encrypted buffer
465 ucx_buffer_write(enc->space, 1, enc->size, p->content); 459 cxBufferWrite(enc->space, 1, enc->size, p->content);
466 460
467 ucx_buffer_free(enc); 461 cxBufferFree(enc);
468 462
469 FILE *out = fopen(file, "w"); 463 FILE *out = fopen(file, "w");
470 if(!out) { 464 if(!out) {
471 return 1; 465 return 1;
472 } 466 }

mercurial