annotate insert.cpp @ 601:82d23418d867

Fix some fd leaks in the command-line binary Strictly speaking, they're not really leaks, because the only codepath that suffers from these leaks exits immediately afterwards. On the other hand, this fix makes valgrind on e.g. tests/0025 happier, going from 5 errors to none.
author mas01cr
date Fri, 14 Aug 2009 16:39:32 +0000
parents 6ad0a6e67d4c
children
rev   line source
mas01cr@498 1 extern "C" {
mas01cr@498 2 #include "audioDB_API.h"
mas01cr@498 3 }
mas01cr@498 4 #include "audioDB-internals.h"
mas01cr@239 5
mas01cr@498 6 static bool audiodb_enough_data_space_free(adb_t *adb, off_t size) {
mas01cr@498 7 adb_header_t *header = adb->header;
mas01cr@509 8 if(header->flags & ADB_HEADER_FLAG_REFERENCES) {
mas01cr@498 9 return true;
mas01cr@498 10 } else {
mas01cr@498 11 /* FIXME: timesTableOffset isn't necessarily the next biggest
mas01cr@498 12 * offset after dataOffset. Maybe make the offsets into an array
mas01cr@498 13 * that we can iterate over... */
mas01cr@498 14 return (header->timesTableOffset >
mas01cr@498 15 (header->dataOffset + header->length + size));
mas01cr@239 16 }
mas01cr@239 17 }
mas01cr@239 18
mas01cr@498 19 static bool audiodb_enough_per_file_space_free(adb_t *adb) {
mas01cr@498 20 /* FIXME: the comment above about the ordering of the tables applies
mas01cr@498 21 here too. */
mas01cr@498 22 adb_header_t *header = adb->header;
mas01cr@498 23 off_t file_table_length = header->trackTableOffset - header->fileTableOffset;
mas01cr@498 24 off_t track_table_length = header->dataOffset - header->trackTableOffset;
mas01cr@509 25 int fmaxfiles = file_table_length / ADB_FILETABLE_ENTRY_SIZE;
mas01cr@509 26 int tmaxfiles = track_table_length / ADB_TRACKTABLE_ENTRY_SIZE;
mas01cr@498 27 /* maxfiles is the _minimum_ of the two. Do not be confused... */
mas01cr@498 28 int maxfiles = fmaxfiles > tmaxfiles ? tmaxfiles : fmaxfiles;
mas01cr@509 29 if(header->flags & ADB_HEADER_FLAG_REFERENCES) {
mas01cr@498 30 /* by default, these tables are created with the same size as the
mas01cr@498 31 * fileTable (which should be called key_table); relying on that
mas01cr@498 32 * always being the case, though, smacks of optimism, so instead
mas01cr@498 33 * we code defensively... */
mas01cr@498 34 off_t data_table_length = header->timesTableOffset - header->dataOffset;
mas01cr@498 35 off_t times_table_length = header->powerTableOffset - header->timesTableOffset;
mas01cr@498 36 off_t power_table_length = header->dbSize - header->powerTableOffset;
mas01cr@509 37 int dmaxfiles = data_table_length / ADB_FILETABLE_ENTRY_SIZE;
mas01cr@509 38 int timaxfiles = times_table_length / ADB_FILETABLE_ENTRY_SIZE;
mas01cr@509 39 int pmaxfiles = power_table_length / ADB_FILETABLE_ENTRY_SIZE;
mas01cr@498 40 /* ... even though it means a certain amount of tedium. */
mas01cr@498 41 maxfiles = maxfiles > dmaxfiles ? dmaxfiles : maxfiles;
mas01cr@498 42 maxfiles = maxfiles > timaxfiles ? timaxfiles : maxfiles;
mas01cr@498 43 maxfiles = maxfiles > pmaxfiles ? pmaxfiles : maxfiles;
mas01cr@498 44 }
mas01cr@498 45 return (header->numFiles < (unsigned int) maxfiles);
mas01cr@498 46 }
mas01cr@498 47
mas01cr@498 48 /*
mas01cr@498 49 * Hey, look, a comment. Normally I wouldn't bother, as the code
mas01cr@498 50 * should be self-documenting, but a lot of logic is concentrated in
mas01cr@498 51 * this one place, so let's give an overview beforehand. To insert a
mas01cr@498 52 * datum into the database, we:
mas01cr@498 53 *
mas01cr@498 54 * 1. check write permission;
mas01cr@498 55 * 2. check for enough space;
mas01cr@498 56 * 3. check that datum->dim and adb->header->dim agree (or that the
mas01cr@498 57 * header dimension is zero, in which case write datum->dim to
mas01cr@498 58 * adb->header->dim).
mas01cr@498 59 * 4. check for presence of datum->key in adb->keymap;
mas01cr@509 60 * 5. check for consistency between power and ADB_HEADER_FLAG_POWER,
mas01cr@509 61 * and times and ADB_HEADER_FLAG_TIMES;
mas01cr@498 62 * 6. write in data, power, times as appropriate; add to track
mas01cr@498 63 * and key tables too;
mas01cr@509 64 * 7. if ADB_HEADER_FLAG_L2NORM and !ADB_HEADER_FLAG_REFERENCES,
mas01cr@509 65 * compute norms and fill in table;
mas01cr@498 66 * 8. update adb->keys, adb->keymap, adb->track_lengths,
mas01cr@498 67 * adb->track_offsets and adb->header;
mas01cr@498 68 * 9. sync adb->header with disk.
mas01cr@498 69 *
mas01cr@498 70 * Step 9 essentially commits the transaction; until we update
mas01cr@498 71 * header->length, nothing will recognize the newly-written data. In
mas01cr@498 72 * principle, if it fails, we should roll back, which we can in fact
mas01cr@498 73 * do on the assumption that nothing in step 8 can ever fail; on the
mas01cr@498 74 * other hand, if it's failed, then it's unlikely that rolling back by
mas01cr@498 75 * syncing the original header back to disk is going to work
mas01cr@498 76 * desperately well. We should perhaps take an operating-system lock
mas01cr@498 77 * around step 9, so that we can't be interrupted part-way through
mas01cr@498 78 * (except of course for SIGKILL, but if we're hit with that we will
mas01cr@498 79 * always lose).
mas01cr@498 80 */
mas01cr@498 81 static int audiodb_insert_datum_internal(adb_t *adb, adb_datum_internal_t *datum) {
mas01cr@498 82
mas01cr@498 83 off_t size, offset, nfiles;
mas01cr@498 84 double *l2norm_buffer = NULL;
mas01cr@498 85
mas01cr@498 86 /* 1. check write permission; */
mas01cr@498 87 if(!(adb->flags & O_RDWR)) {
mas01cr@498 88 return 1;
mas01cr@498 89 }
mas01cr@498 90 /* 2. check for enough space; */
mas01cr@498 91 size = sizeof(double) * datum->nvectors * datum->dim;
mas01cr@498 92 if(!audiodb_enough_data_space_free(adb, size)) {
mas01cr@498 93 return 1;
mas01cr@498 94 }
mas01cr@498 95 if(!audiodb_enough_per_file_space_free(adb)) {
mas01cr@498 96 return 1;
mas01cr@498 97 }
mas01cr@498 98 /* 3. check that datum->dim and adb->header->dim agree (or that the
mas01cr@498 99 * header dimension is zero, in which case write datum->dim to
mas01cr@498 100 * adb->header->dim).
mas01cr@498 101 */
mas01cr@498 102 if(adb->header->dim == 0) {
mas01cr@498 103 adb->header->dim = datum->dim;
mas01cr@498 104 } else if (adb->header->dim != datum->dim) {
mas01cr@498 105 return 1;
mas01cr@498 106 }
mas01cr@498 107 /* 4. check for presence of datum->key in adb->keymap; */
mas01cr@498 108 if(adb->keymap->count(datum->key)) {
mas01cr@498 109 /* not part of an explicit API/ABI, but we need a distinguished
mas01cr@498 110 value in this circumstance to preserve somewhat wonky behaviour
mas01cr@498 111 of audioDB::batchinsert. */
mas01cr@498 112 return 2;
mas01cr@498 113 }
mas01cr@509 114 /* 5. check for consistency between power and ADB_HEADER_FLAG_POWER,
mas01cr@509 115 * and times and ADB_HEADER_FLAG_TIMES;
mas01cr@498 116 */
mas01cr@509 117 if((datum->power && !(adb->header->flags & ADB_HEADER_FLAG_POWER)) ||
mas01cr@509 118 ((adb->header->flags & ADB_HEADER_FLAG_POWER) && !datum->power)) {
mas01cr@498 119 return 1;
mas01cr@498 120 }
mas01cr@509 121 if(datum->times && !(adb->header->flags & ADB_HEADER_FLAG_TIMES)) {
mas01cr@498 122 if(adb->header->numFiles == 0) {
mas01cr@509 123 adb->header->flags |= ADB_HEADER_FLAG_TIMES;
mas01cr@498 124 } else {
mas01cr@498 125 return 1;
mas01cr@239 126 }
mas01cr@509 127 } else if ((adb->header->flags & ADB_HEADER_FLAG_TIMES) && !datum->times) {
mas01cr@498 128 return 1;
mas01cr@498 129 }
mas01cr@498 130 /* 6. write in data, power, times as appropriate; add to track
mas01cr@498 131 * and key tables too;
mas01cr@498 132 */
mas01cr@498 133 offset = adb->header->length;
mas01cr@498 134 nfiles = adb->header->numFiles;
mas01cr@498 135
mas01cr@498 136 /* FIXME: checking for all these lseek()s */
mas01cr@596 137 lseek_set_or_goto_error(adb->fd, adb->header->fileTableOffset + nfiles * ADB_FILETABLE_ENTRY_SIZE);
mas01cr@498 138 write_or_goto_error(adb->fd, datum->key, strlen(datum->key)+1);
mas01cr@596 139 lseek_set_or_goto_error(adb->fd, adb->header->trackTableOffset + nfiles * ADB_TRACKTABLE_ENTRY_SIZE);
mas01cr@509 140 write_or_goto_error(adb->fd, &datum->nvectors, ADB_TRACKTABLE_ENTRY_SIZE);
mas01cr@509 141 if(adb->header->flags & ADB_HEADER_FLAG_REFERENCES) {
mas01cr@498 142 char cwd[PATH_MAX];
mas01cr@498 143 char slash = '/';
mas01cr@498 144
mas01cr@498 145 if(!getcwd(cwd, PATH_MAX)) {
mas01cr@498 146 goto error;
mas01cr@498 147 }
mas01cr@596 148 lseek_set_or_goto_error(adb->fd, adb->header->dataOffset + nfiles * ADB_FILETABLE_ENTRY_SIZE);
mas01cr@498 149 if(*((char *) datum->data) != '/') {
mas01cr@498 150 write_or_goto_error(adb->fd, cwd, strlen(cwd));
mas01cr@498 151 write_or_goto_error(adb->fd, &slash, 1);
mas01cr@498 152 }
mas01cr@498 153 write_or_goto_error(adb->fd, datum->data, strlen((const char *) datum->data)+1);
mas01cr@498 154 if(datum->power) {
mas01cr@596 155 lseek_set_or_goto_error(adb->fd, adb->header->powerTableOffset + nfiles * ADB_FILETABLE_ENTRY_SIZE);
mas01cr@498 156 if(*((char *) datum->power) != '/') {
mas01cr@498 157 write_or_goto_error(adb->fd, cwd, strlen(cwd));
mas01cr@498 158 write_or_goto_error(adb->fd, &slash, 1);
mas01cr@498 159 }
mas01cr@498 160 write_or_goto_error(adb->fd, datum->power, strlen((const char *) datum->power)+1);
mas01cr@498 161 }
mas01cr@498 162 if(datum->times) {
mas01cr@596 163 lseek_set_or_goto_error(adb->fd, adb->header->timesTableOffset + nfiles * ADB_FILETABLE_ENTRY_SIZE);
mas01cr@498 164 if(*((char *) datum->times) != '/') {
mas01cr@498 165 write_or_goto_error(adb->fd, cwd, strlen(cwd));
mas01cr@498 166 write_or_goto_error(adb->fd, &slash, 1);
mas01cr@498 167 }
mas01cr@498 168 write_or_goto_error(adb->fd, datum->times, strlen((const char *) datum->times)+1);
mas01cr@498 169 }
mas01cr@498 170 } else {
mas01cr@596 171 lseek_set_or_goto_error(adb->fd, adb->header->dataOffset + offset);
mas01cr@498 172 write_or_goto_error(adb->fd, datum->data, sizeof(double) * datum->nvectors * datum->dim);
mas01cr@498 173 if(datum->power) {
mas01cr@596 174 lseek_set_or_goto_error(adb->fd, adb->header->powerTableOffset + offset / datum->dim);
mas01cr@498 175 write_or_goto_error(adb->fd, datum->power, sizeof(double) * datum->nvectors);
mas01cr@498 176 }
mas01cr@498 177 if(datum->times) {
mas01cr@596 178 lseek_set_or_goto_error(adb->fd, adb->header->timesTableOffset + offset / datum->dim * 2);
mas01cr@498 179 write_or_goto_error(adb->fd, datum->times, sizeof(double) * datum->nvectors * 2);
mas01cr@498 180 }
mas01cr@498 181 }
mas01cr@498 182
mas01cr@509 183 /* 7. if ADB_HEADER_FLAG_L2NORM and !ADB_HEADER_FLAG_REFERENCES,
mas01cr@509 184 * compute norms and fill in table;
mas01cr@498 185 */
mas01cr@509 186 if((adb->header->flags & ADB_HEADER_FLAG_L2NORM) &&
mas01cr@509 187 !(adb->header->flags & ADB_HEADER_FLAG_REFERENCES)) {
mas01cr@498 188 l2norm_buffer = (double *) malloc(datum->nvectors * sizeof(double));
mas01mc@324 189
mas01cr@498 190 audiodb_l2norm_buffer((double *) datum->data, datum->dim, datum->nvectors, l2norm_buffer);
mas01cr@596 191 lseek_set_or_goto_error(adb->fd, adb->header->l2normTableOffset + offset / datum->dim);
mas01cr@498 192 write_or_goto_error(adb->fd, l2norm_buffer, sizeof(double) * datum->nvectors);
mas01cr@498 193 free(l2norm_buffer);
mas01cr@498 194 l2norm_buffer = NULL;
mas01cr@498 195 }
mas01cr@498 196
mas01cr@498 197 /* 8. update adb->keys, adb->keymap, adb->track_lengths,
mas01cr@498 198 * adb->track_offsets and adb->header;
mas01cr@498 199 */
mas01cr@498 200 adb->keys->push_back(datum->key);
mas01cr@498 201 (*adb->keymap)[datum->key] = adb->header->numFiles;
mas01cr@498 202 adb->track_lengths->push_back(datum->nvectors);
mas01cr@498 203 adb->track_offsets->push_back(offset);
mas01cr@498 204 adb->header->numFiles += 1;
mas01cr@498 205 adb->header->length += sizeof(double) * datum->nvectors * datum->dim;
mas01cr@498 206
mas01cr@498 207 /* 9. sync adb->header with disk. */
mas01cr@498 208 return audiodb_sync_header(adb);
mas01cr@498 209
mas01cr@498 210 error:
mas01cr@596 211 maybe_free(l2norm_buffer);
mas01cr@498 212 return 1;
mas01cr@498 213 }
mas01cr@498 214
mas01cr@498 215 int audiodb_insert_datum(adb_t *adb, const adb_datum_t *datum) {
mas01cr@509 216 if(adb->header->flags & ADB_HEADER_FLAG_REFERENCES) {
mas01cr@498 217 return 1;
mas01cr@498 218 } else {
mas01cr@498 219 adb_datum_internal_t d;
mas01cr@498 220 d.nvectors = datum->nvectors;
mas01cr@498 221 d.dim = datum->dim;
mas01cr@498 222 d.key = datum->key;
mas01cr@498 223 d.data = datum->data;
mas01cr@498 224 d.times = datum->times;
mas01cr@498 225 d.power = datum->power;
mas01cr@498 226 return audiodb_insert_datum_internal(adb, &d);
mas01cr@498 227 }
mas01cr@498 228 }
mas01cr@498 229
mas01cr@498 230 int audiodb_insert_reference(adb_t *adb, const adb_reference_t *reference) {
mas01cr@509 231 if(!(adb->header->flags & ADB_HEADER_FLAG_REFERENCES)) {
mas01cr@498 232 return 1;
mas01cr@498 233 } else {
mas01cr@498 234 adb_datum_internal_t d;
mas01cr@498 235 struct stat st;
mas01cr@498 236 int fd;
mas01cr@498 237 off_t size;
mas01mc@324 238
mas01cr@498 239 if((fd = open(reference->features, O_RDONLY)) == -1) {
mas01cr@498 240 return 1;
mas01cr@239 241 }
mas01cr@498 242 if(fstat(fd, &st)) {
mas01cr@498 243 goto error;
mas01cr@239 244 }
mas01cr@498 245 read_or_goto_error(fd, &(d.dim), sizeof(uint32_t));
mas01cr@498 246 close(fd);
mas01cr@498 247 fd = 0;
mas01cr@498 248 size = st.st_size - sizeof(uint32_t);
mas01cr@498 249 d.nvectors = size / (sizeof(double) * d.dim);
mas01cr@498 250 d.data = (void *) reference->features;
mas01cr@498 251 if(reference->power) {
mas01cr@498 252 if(stat(reference->power, &st)) {
mas01cr@498 253 return 1;
mas01cr@498 254 }
mas01cr@498 255 }
mas01cr@498 256 d.power = (void *) reference->power;
mas01cr@498 257 if(reference->times) {
mas01cr@498 258 if(stat(reference->times, &st)) {
mas01cr@498 259 return 1;
mas01cr@498 260 }
mas01cr@498 261 }
mas01cr@498 262 d.times = (void *) reference->times;
mas01cr@498 263 d.key = reference->key ? reference->key : reference->features;
mas01cr@498 264 return audiodb_insert_datum_internal(adb, &d);
mas01cr@498 265 error:
mas01cr@498 266 if(fd) {
mas01cr@498 267 close(fd);
mas01cr@498 268 }
mas01cr@498 269 return 1;
mas01cr@498 270 }
mas01cr@498 271 }
mas01cr@498 272
mas01cr@580 273 int audiodb_really_free_datum(adb_datum_t *datum) {
mas01cr@498 274 if(datum->data) {
mas01cr@498 275 free(datum->data);
mas01cr@498 276 datum->data = NULL;
mas01cr@498 277 }
mas01cr@498 278 if(datum->power) {
mas01cr@498 279 free(datum->power);
mas01cr@498 280 datum->power = NULL;
mas01cr@498 281 }
mas01cr@498 282 if(datum->times) {
mas01cr@498 283 free(datum->times);
mas01cr@498 284 datum->times = NULL;
mas01cr@498 285 }
mas01cr@498 286 return 0;
mas01cr@498 287 }
mas01cr@498 288
mas01cr@498 289 int audiodb_insert_create_datum(adb_insert_t *insert, adb_datum_t *datum) {
mas01cr@498 290 int fd = 0;
mas01cr@498 291 FILE *file = NULL;
mas01cr@498 292 struct stat st;
mas01cr@498 293 off_t size;
mas01cr@498 294
mas01cr@498 295 datum->data = NULL;
mas01cr@498 296 datum->power = NULL;
mas01cr@498 297 datum->times = NULL;
mas01cr@498 298 if((fd = open(insert->features, O_RDONLY)) == -1) {
mas01cr@498 299 goto error;
mas01cr@498 300 }
mas01cr@498 301 if(fstat(fd, &st)) {
mas01cr@498 302 goto error;
mas01cr@498 303 }
mas01cr@498 304 read_or_goto_error(fd, &(datum->dim), sizeof(uint32_t));
mas01cr@498 305 size = st.st_size - sizeof(uint32_t);
mas01cr@498 306 datum->nvectors = size / (sizeof(double) * datum->dim);
mas01cr@498 307 datum->data = (double *) malloc(size);
mas01cr@498 308 if(!datum->data) {
mas01cr@498 309 goto error;
mas01cr@498 310 }
mas01cr@498 311 read_or_goto_error(fd, datum->data, size);
mas01cr@498 312 close(fd);
mas01cr@498 313 fd = 0;
mas01cr@498 314 if(insert->power) {
mas01cr@498 315 int dim;
mas01cr@498 316 if((fd = open(insert->power, O_RDONLY)) == -1) {
mas01cr@498 317 goto error;
mas01cr@498 318 }
mas01cr@498 319 if(fstat(fd, &st)) {
mas01cr@498 320 goto error;
mas01cr@498 321 }
mas01cr@498 322 /* This cast is so non-trivial that it deserves a comment.
mas01cr@498 323 *
mas01cr@498 324 * The data types in this expression, left to right, are: off_t,
mas01cr@498 325 * size_t, off_t, uint32_t. The rules for conversions in
mas01cr@498 326 * arithmetic expressions with mixtures of integral types are
mas01cr@498 327 * essentially that the widest type wins, with unsigned types
mas01cr@498 328 * winning on a tie-break.
mas01cr@498 329 *
mas01cr@498 330 * Because we are enforcing (through the use of sufficient
mas01cr@498 331 * compiler flags, if necessary) that off_t be a (signed) 64-bit
mas01cr@498 332 * type, the only variability in this set of types is in fact the
mas01cr@498 333 * size_t. On 32-bit machines, size_t is uint32_t and so the
mas01cr@498 334 * coercions on both sides of the equality end up promoting
mas01cr@498 335 * everything to int64_t, which is fine. On 64-bit machines,
mas01cr@498 336 * however, the left hand side is promoted to a uint64_t, while
mas01cr@498 337 * the right hand side remains int64_t.
mas01cr@498 338 *
mas01cr@498 339 * The mixture of signed and unsigned types in comparisons is Evil
mas01cr@498 340 * Bad and Wrong, and gcc complains about it. (It's right to do
mas01cr@498 341 * so, actually). Of course in this case it will never matter
mas01cr@498 342 * because of the particular relationships between all of these
mas01cr@498 343 * numbers, so we just cast the left hand side to off_t, which
mas01cr@498 344 * will do the right thing for us on all platforms.
mas01cr@498 345 *
mas01cr@498 346 * I hate C.
mas01cr@594 347 *
mas01cr@594 348 * Addendum: the above reasoning is skewered on Win32, where off_t
mas01cr@594 349 * is apparently signed 32-bit always (i.e. no large-file
mas01cr@594 350 * support). So now, we cast datum->dim to size_t, so that our
mas01cr@594 351 * types are the same on both sides. I hate C even more.
mas01cr@498 352 */
mas01cr@594 353 if((st.st_size - sizeof(uint32_t)) != (size / (size_t) datum->dim)) {
mas01cr@498 354 goto error;
mas01cr@498 355 }
mas01cr@498 356 read_or_goto_error(fd, &dim, sizeof(uint32_t));
mas01cr@498 357 if(dim != 1) {
mas01cr@498 358 goto error;
mas01cr@498 359 }
mas01cr@498 360 datum->power = (double *) malloc(size / datum->dim);
mas01cr@498 361 if(!datum->power) {
mas01cr@498 362 goto error;
mas01cr@498 363 }
mas01cr@498 364 read_or_goto_error(fd, datum->power, size / datum->dim);
mas01cr@498 365 close(fd);
mas01cr@498 366 }
mas01cr@498 367 if(insert->times) {
mas01cr@498 368 double t, *tp;
mas01cr@498 369 if(!(file = fopen(insert->times, "r"))) {
mas01cr@498 370 goto error;
mas01cr@498 371 }
mas01cr@498 372 datum->times = (double *) malloc(2 * size / datum->dim);
mas01cr@498 373 if(!datum->times) {
mas01cr@498 374 goto error;
mas01cr@498 375 }
mas01cr@498 376 if(fscanf(file, " %lf", &t) != 1) {
mas01cr@498 377 goto error;
mas01cr@498 378 }
mas01cr@498 379 tp = datum->times;
mas01cr@498 380 *tp++ = t;
mas01cr@498 381 for(unsigned int n = 0; n < datum->nvectors - 1; n++) {
mas01cr@498 382 if(fscanf(file, " %lf", &t) != 1) {
mas01cr@498 383 goto error;
mas01cr@498 384 }
mas01cr@498 385 *tp++ = t;
mas01cr@498 386 *tp++ = t;
mas01cr@498 387 }
mas01cr@498 388 if(fscanf(file, " %lf", &t) != 1) {
mas01cr@498 389 goto error;
mas01cr@498 390 }
mas01cr@498 391 *tp = t;
mas01cr@498 392 fclose(file);
mas01cr@498 393 }
mas01cr@498 394 datum->key = insert->key ? insert->key : insert->features;
mas01cr@498 395 return 0;
mas01cr@498 396
mas01cr@498 397 error:
mas01cr@498 398 if(fd > 0) {
mas01cr@498 399 close(fd);
mas01cr@498 400 }
mas01cr@498 401 if(file) {
mas01cr@498 402 fclose(file);
mas01cr@498 403 }
mas01cr@580 404 audiodb_really_free_datum(datum);
mas01cr@498 405 return 1;
mas01cr@498 406 }
mas01cr@498 407
mas01cr@498 408 int audiodb_insert(adb_t *adb, adb_insert_t *insert) {
mas01cr@509 409 if(adb->header->flags & ADB_HEADER_FLAG_REFERENCES) {
mas01cr@498 410 adb_reference_t *reference = insert;
mas01cr@498 411 int err;
mas01cr@498 412 err = audiodb_insert_reference(adb, reference);
mas01cr@498 413
mas01cr@498 414 if(err == 2) {
mas01cr@498 415 return 0;
mas01cr@498 416 } else {
mas01cr@498 417 return err;
mas01cr@498 418 }
mas01cr@498 419 } else {
mas01cr@498 420 adb_datum_t datum;
mas01cr@498 421 int err;
mas01cr@498 422
mas01cr@498 423 if(audiodb_insert_create_datum(insert, &datum)) {
mas01cr@498 424 return 1;
mas01cr@498 425 }
mas01cr@498 426 err = audiodb_insert_datum(adb, &datum);
mas01cr@580 427 audiodb_really_free_datum(&datum);
mas01cr@498 428
mas01cr@498 429 if(err == 2) {
mas01cr@498 430 return 0;
mas01cr@498 431 } else {
mas01cr@498 432 return err;
mas01cr@239 433 }
mas01cr@239 434 }
mas01cr@239 435 }
mas01cr@239 436
mas01cr@498 437 int audiodb_batchinsert(adb_t *adb, adb_insert_t *insert, unsigned int size) {
mas01cr@498 438 int err;
mas01cr@498 439 for(unsigned int n = 0; n < size; n++) {
mas01cr@498 440 if((err = audiodb_insert(adb, &(insert[n])))) {
mas01cr@498 441 return err;
mas01cr@498 442 }
mas01mc@324 443 }
mas01cr@498 444 return 0;
mas01cr@239 445 }