diff --git a/src/database.c b/src/database.c index 5ecde2e..81812c7 100644 --- a/src/database.c +++ b/src/database.c @@ -61,53 +61,63 @@ imdb_create(const char *path) { return result; } -int imdb_open(imdb_db_t *db, const char *path, int write) -{ +imdb_db_t * +imdb_open(const char *path, int mode, int *error) { + imdb_db_t *db = NULL; ssize_t bytes = 0; struct stat st; char buf[IMDB_REC_LEN] = "\0"; int flags = 0, fd = -1; char *p; - assert(db != NULL); - assert(path != NULL); - - memset(db, 0x0, sizeof(imdb_db_t)); + assert(path != NULL); + assert(error != NULL); - errno = 0; if (stat(path, &st) < 0) { - strncpy(db->error, strerror(errno), sizeof(db->error)); - return -1; + *error = -1; + return NULL; } - errno = 0; - if ((fd = open(path, write ? O_RDWR : O_RDONLY)) < 0) { - strncpy(db->error, strerror(errno), sizeof(db->error)); - return -1; + if ((fd = open(path, (mode & IMDB_FLAG_WRITE) ? O_RDWR : O_RDONLY)) < 0) { + *error = -1; + return NULL; } - DB_READ(db, buf, IMDB_REC_LEN, 0); - - if (bytes != IMDB_REC_LEN) { - strncpy(db->error, "Empty or damaged database file", sizeof(db->error)); - return -1; + errno = 0; + bytes = pread(fd, buf, IMDB_REC_LEN, 0); + if (bytes < IMDB_REC_LEN) { + *error = errno ? -1 : -3; /* empty file, damaged database or IO error */ + return NULL; } - if (memcmp("IMDB", buf, 4) != 0) { - strncpy(db->error, "Not a database file", sizeof(db->error)); - return -1; + + p = buf + 0; + if (memcmp("IMDB", p, 4) != 0) { + *error = -3; /* Not a database file */ + return NULL; } - if (atoi(buf + 6) != IMDB_VERSION) { - strncpy(db->error, "Database version mismatch", sizeof(db->error)); - return -1; + + p = buf + 6; + if (atoi(p) != IMDB_VERSION) { + *error = -4; /* Database version mismatch */ + return NULL; } - if (memcmp("CAPS", buf + 10, 4) != 0) { - strncpy(db->error, "Can't read database capabilities", sizeof(db->error)); - return -1; + + p = buf + 10; + if (memcmp("CAPS", p, 4) != 0) { + *error = -3; /* Can't read database capabilities */ + return NULL; } - if (write) + if (mode & IMDB_FLAG_WRITE) flags |= IMDB_FLAG_WRITE; + /* all seems to be ok */ + + if ((db = calloc(1, sizeof(imdb_db_t))) == NULL) { + *error = -2; /* out of memory */ + return NULL; + } + p = buf + 16; for (size_t i = 0; i < 8 && *p != '\0'; p++) { switch (*p) { @@ -124,21 +134,16 @@ int imdb_open(imdb_db_t *db, const char *path, int write) strncpy(db->path, path, sizeof(db->path)); - return 0; + return db; } -int imdb_close(imdb_db_t *db) +void +imdb_close(imdb_db_t *db) { assert(db != NULL); - errno = 0; - if (close(db->fd) != 0) { - strncpy(db->error, strerror(errno), sizeof(db->error)); - return -1; - } - db->fd = -1; - - return 0; + if (db->fd >= 0) + close(db->fd); } int imdb_read_rec(imdb_db_t *db, imdb_rec_t *rec) diff --git a/src/database.h b/src/database.h index e384214..739bb9a 100644 --- a/src/database.h +++ b/src/database.h @@ -103,15 +103,31 @@ int imdb_write_blk(imdb_db_t *db, imdb_block_t *blk); /** * @brief Creates empty database at given path - * @param path Where to create database + * @param path Path to database * @returns true on success, and false on error * @note See errno value for details * @todo 2nd arg: caps */ bool imdb_create(const char *path); -int imdb_open (imdb_db_t *db, const char *path, int write); -int imdb_close (imdb_db_t *db); +/** + * @brief Open database at given path + * @param path Path to database + * @param mode Database open modes. See IMDB_FLAG_* defines above + * @param error Pointer to error code storage + * @returns Pointer to database handle on success, NULL on error + * -1 -- system error, see @a errno for details + * -2 -- malloc() failed + * -3 -- damaged database + * -4 -- database version mismatch + */ +imdb_db_t * imdb_open(const char *path, int mode, int *error); + +/** + * @brief Close database and free associated resources + * @param db Database handle + */ +void imdb_close(imdb_db_t *db); float ratio_from_rec_data(unsigned char * const data);