X-Git-Url: http://git.tuebingen.mpg.de/?p=osl.git;a=blobdiff_plain;f=osl.c;h=f751302abc38a4327ed76c789954046279890592;hp=b64a3c846f9ae4222aa5d53f4469fe204202170d;hb=d8ae0ffdecd9383382d861dc6fe34bdd4f07a5b9;hpb=5952112a37ecdaedf3b76e08f97d307f1056c512 diff --git a/osl.c b/osl.c index b64a3c8..f751302 100644 --- a/osl.c +++ b/osl.c @@ -10,6 +10,7 @@ #include "log.h" +#include "osl.h" #include "error.h" #include "fd.h" #include "list.h" @@ -24,23 +25,86 @@ * resulting string is imposed. * * \return This function either returns a pointer to a string that must be - * freed by the caller or aborts without returning. + * freed by the caller or \p NULL if memory allocation failed. * * \sa printf(3). */ static __must_check __printf_1_2 __malloc char *make_message(const char *fmt, ...) { - char *msg; + int n; + size_t size = 100; + char *p = malloc(size); + + if (!p) + return NULL; + while (1) { + char *q; + va_list ap; + /* Try to print in the allocated space. */ + va_start(ap, fmt); + n = vsnprintf(p, size, fmt, ap); + va_end(ap); + /* If that worked, return the string. */ + if (n > -1 && n < size) + break; + /* Else try again with more space. */ + if (n > -1) /* glibc 2.1 */ + size = n + 1; /* precisely what is needed */ + else /* glibc 2.0 */ + size *= 2; /* twice the old size */ + q = realloc(p, size); + if (!q) { + free(p); + return NULL; + } + } + return p; +} - VSPRINTF(fmt, msg); - return msg; +/* Taken from Drepper: How to write shared libraries, Appendix B. */ +#include +#define MSGSTRFIELD(line) MSGSTRFIELD1(line) +#define MSGSTRFIELD1(line) str##line +static const union msgstr_t { + struct { +#define _S(n, s) char MSGSTRFIELD(__LINE__)[sizeof(s)]; +#include "errtab.h" +#undef _S + }; + char str[0]; +} msgstr = { { +#define _S(n, s) s, +#include "errtab.h" +#undef _S +} }; +static const unsigned int errmsgidx[] = { +#define _S(n, s) [n] = offsetof(union msgstr_t, MSGSTRFIELD(__LINE__)), +#include "errtab.h" +#undef _S +}; + +__export const char *osl_strerror(int num) +{ + if (IS_SYSTEM_ERROR(num)) + return strerror((num) & ((1 << SYSTEM_ERROR_BIT) - 1)); + return msgstr.str + errmsgidx[num]; +} + +static int loglevel; + +static void __attribute ((constructor)) init_loglevel(void) +{ + char *p = getenv("OSL_LOGLEVEL"); + + /* don't log anything if unset */ + loglevel = p? atoi(p) : EMERG + 1; } /** * The log function. * * \param ll Loglevel. - * \param fml Usual format string. + * \param fmt Usual format string. * * All XXX_LOG() macros use this function. */ @@ -52,7 +116,7 @@ __printf_2_3 void __log(int ll, const char* fmt,...) time_t t1; char str[255] = ""; - if (ll < 2) + if (ll < loglevel) return; outfd = stderr; time(&t1); @@ -76,14 +140,14 @@ __printf_2_3 void __log(int ll, const char* fmt,...) * contains the resulting offset location as measured in bytes from the * beginning of the file. * - * \return Positive on success. Otherwise, the function returns \p -E_LSEEK. + * \return Positive on success. Otherwise, the function returns \p -E_OSL_LSEEK. * * \sa lseek(2). */ -int para_lseek(int fd, off_t *offset, int whence) +static int __lseek(int fd, off_t *offset, int whence) { *offset = lseek(fd, *offset, whence); - int ret = -E_LSEEK; + int ret = -E_OSL_LSEEK; if (*offset == -1) return ret; return 1; @@ -100,11 +164,11 @@ int para_lseek(int fd, off_t *offset, int whence) * occurred during the write. * * \return On success, the number of bytes written is returned, otherwise, the - * function returns \p -E_WRITE. + * function returns \p -E_OSL_WRITE. * * \sa write(2). */ -ssize_t para_write(int fd, const void *buf, size_t size) +static ssize_t __write(int fd, const void *buf, size_t size) { ssize_t ret; @@ -112,7 +176,7 @@ ssize_t para_write(int fd, const void *buf, size_t size) ret = write(fd, buf, size); if ((ret < 0) && (errno == EAGAIN || errno == EINTR)) continue; - return ret >= 0? ret : -E_WRITE; + return ret >= 0? ret : -E_OSL_WRITE; } } @@ -131,12 +195,12 @@ ssize_t para_write(int fd, const void *buf, size_t size) * * \sa para_write(). */ -ssize_t para_write_all(int fd, const void *buf, size_t size) +static ssize_t write_all(int fd, const void *buf, size_t size) { // DEBUG_LOG("writing %zu bytes\n", size); const char *b = buf; while (size) { - ssize_t ret = para_write(fd, b, size); + ssize_t ret = __write(fd, b, size); // DEBUG_LOG("ret: %zd\n", ret); if (ret < 0) return ret; @@ -152,20 +216,17 @@ ssize_t para_write_all(int fd, const void *buf, size_t size) * \param buf The buffer to write to the file. * \param size The size of \a buf. * - * \return Positive on success, negative on errors. Possible errors include: - * any errors from para_open() or para_write(). - * - * \sa para_open(), para_write(). + * \return Standard. */ -int para_write_file(const char *filename, const void *buf, size_t size) +static int write_file(const char *filename, const void *buf, size_t size) { int ret, fd; - ret = para_open(filename, O_WRONLY | O_CREAT | O_EXCL, 0644); + ret = osl_open(filename, O_WRONLY | O_CREAT | O_EXCL, 0644); if (ret < 0) return ret; fd = ret; - ret = para_write_all(fd, buf, size); + ret = write_all(fd, buf, size); if (ret < 0) goto out; ret = 1; @@ -180,21 +241,21 @@ static int append_file(const char *filename, char *header, size_t header_size, int ret, fd; // DEBUG_LOG("appending %zu + %zu bytes\n", header_size, data_size); - ret = para_open(filename, O_WRONLY | O_CREAT | O_APPEND, 0644); + ret = osl_open(filename, O_WRONLY | O_CREAT | O_APPEND, 0644); if (ret < 0) return ret; fd = ret; if (header && header_size) { - ret = para_write_all(fd, header, header_size); + ret = write_all(fd, header, header_size); if (ret < 0) goto out; } - ret = para_write_all(fd, data, data_size); + ret = write_all(fd, data, data_size); if (ret < 0) goto out; if (new_pos) { off_t offset = 0; - ret = para_lseek(fd, &offset, SEEK_END); + ret = __lseek(fd, &offset, SEEK_END); if (ret < 0) goto out; // DEBUG_LOG("new file size: " FMT_OFF_T "\n", offset); @@ -206,105 +267,21 @@ out: return ret; } -/** - * Traverse the given directory recursively. - * - * \param dirname The directory to traverse. - * \param func The function to call for each entry. - * \param private_data Pointer to an arbitrary data structure. - * - * For each regular file under \a dirname, the supplied function \a func is - * called. The full path of the regular file and the \a private_data pointer - * are passed to \a func. Directories for which the calling process has no - * permissions to change to are silently ignored. - * - * \return Standard. - */ -int for_each_file_in_dir(const char *dirname, - int (*func)(const char *, void *), void *private_data) -{ - DIR *dir; - struct dirent *entry; - int cwd_fd, ret2, ret = para_opendir(dirname, &dir, &cwd_fd); - - if (ret < 0) - return ret == -ERRNO_TO_ERROR(EACCES)? 1 : ret; - /* scan cwd recursively */ - while ((entry = readdir(dir))) { - mode_t m; - char *tmp; - struct stat s; - - if (!strcmp(entry->d_name, ".")) - continue; - if (!strcmp(entry->d_name, "..")) - continue; - if (lstat(entry->d_name, &s) == -1) - continue; - m = s.st_mode; - if (!S_ISREG(m) && !S_ISDIR(m)) - continue; - tmp = make_message("%s/%s", dirname, entry->d_name); - if (!S_ISDIR(m)) { - ret = func(tmp, private_data); - free(tmp); - if (ret < 0) - goto out; - continue; - } - /* directory */ - ret = for_each_file_in_dir(tmp, func, private_data); - free(tmp); - if (ret < 0) - goto out; - } - ret = 1; -out: - closedir(dir); - ret2 = para_fchdir(cwd_fd); - if (ret2 < 0 && ret >= 0) - ret = ret2; - close(cwd_fd); - return ret; -} - static int verify_name(const char *name) { if (!name) - return -E_BAD_NAME; + return -E_OSL_BAD_NAME; if (!*name) - return -E_BAD_NAME; + return -E_OSL_BAD_NAME; if (strchr(name, '/')) - return -E_BAD_NAME; + return -E_OSL_BAD_NAME; if (!strcmp(name, "..")) - return -E_BAD_NAME; + return -E_OSL_BAD_NAME; if (!strcmp(name, ".")) - return -E_BAD_NAME; + return -E_OSL_BAD_NAME; return 1; } -/** - * Compare two osl objects pointing to unsigned integers of 32 bit size. - * - * \param obj1 Pointer to the first integer. - * \param obj2 Pointer to the second integer. - * - * \return The values required for an osl compare function. - * - * \sa osl_compare_func, osl_hash_compare(). - */ -int uint32_compare(const struct osl_object *obj1, const struct osl_object *obj2) -{ - uint32_t d1 = read_u32((const char *)obj1->data); - uint32_t d2 = read_u32((const char *)obj2->data); - - if (d1 < d2) - return 1; - if (d1 > d2) - return -1; - return 0; -} - /** * Compare two osl objects pointing to hash values. * @@ -325,6 +302,8 @@ static char *disk_storage_dirname(const struct osl_table *t, unsigned col_num, { char *dirname, *column_name = column_filename(t, col_num); + if (!column_name) + return NULL; if (!(t->desc->flags & OSL_LARGE_TABLE)) return column_name; dirname = make_message("%s/%.2s", column_name, ds_name); @@ -349,7 +328,9 @@ static int disk_storage_name_of_row(const struct osl_table *t, if (ret < 0) return ret; *name = disk_storage_name_of_object(t, &obj); - return 1; + if (*name) + return 1; + return -ERRNO_TO_ERROR(ENOMEM); } static void column_name_hash(const char *col_name, HASH_TYPE *hash) @@ -362,11 +343,11 @@ static int init_column_descriptions(struct osl_table *t) int i, j, ret; const struct osl_column_description *cd; - ret = -E_BAD_TABLE_DESC; + ret = -E_OSL_BAD_TABLE_DESC; ret = verify_name(t->desc->name); if (ret < 0) goto err; - ret = -E_BAD_DB_DIR; + ret = -E_OSL_BAD_DB_DIR; if (!t->desc->dir && (t->num_disk_storage_columns || t->num_mapped_columns)) goto err; /* the size of the index header without column descriptions */ @@ -375,11 +356,11 @@ static int init_column_descriptions(struct osl_table *t) struct osl_column *col = t->columns + i; if (cd->storage_flags & OSL_RBTREE) { if (!cd->compare_function) - return -E_NO_COMPARE_FUNC; + return -E_OSL_NO_COMPARE_FUNC; } if (cd->storage_type == OSL_NO_STORAGE) continue; - ret = -E_NO_COLUMN_NAME; + ret = -E_OSL_NO_COLUMN_NAME; if (!cd->name || !cd->name[0]) goto err; ret = verify_name(cd->name); @@ -387,7 +368,7 @@ static int init_column_descriptions(struct osl_table *t) goto err; t->index_header_size += index_column_description_size(cd->name); column_name_hash(cd->name, col->name_hash); - ret = -E_DUPLICATE_COL_NAME; + ret = -E_OSL_DUPLICATE_COL_NAME; for (j = i + 1; j < t->desc->num_columns; j++) { const char *name2 = get_column_description(t->desc, j)->name; @@ -410,10 +391,7 @@ err: * of these tests fail. On success, a struct \p osl_table is allocated and * initialized with data derived from \p desc. * - * \return Positive on success, negative on errors. Possible errors include: \p - * E_BAD_TABLE_DESC, \p E_NO_COLUMN_DESC, \p E_NO_COLUMNS, \p - * E_BAD_STORAGE_TYPE, \p E_BAD_STORAGE_FLAGS, \p E_BAD_STORAGE_SIZE, \p - * E_NO_UNIQUE_RBTREE_COLUMN, \p E_NO_RBTREE_COL. + * \return Standard. * * \sa struct osl_table. */ @@ -421,34 +399,40 @@ int init_table_structure(const struct osl_table_description *desc, struct osl_table **table_ptr) { const struct osl_column_description *cd; - struct osl_table *t = para_calloc(sizeof(*t)); - int i, ret = -E_BAD_TABLE_DESC, have_disk_storage_name_column = 0; + struct osl_table *t = calloc(1, sizeof(*t)); + int i, ret = -ERRNO_TO_ERROR(ENOMEM), have_disk_storage_name_column = 0; + if (!t) + return ret; + ret = -E_OSL_BAD_TABLE_DESC; if (!desc) goto err; DEBUG_LOG("creating table structure for '%s' from table " "description\n", desc->name); - ret = -E_NO_COLUMN_DESC; + ret = -E_OSL_NO_COLUMN_DESC; if (!desc->column_descriptions) goto err; - ret = -E_NO_COLUMNS; + ret = -E_OSL_NO_COLUMNS; if (!desc->num_columns) goto err; - t->columns = para_calloc(desc->num_columns * sizeof(struct osl_column)); + ret = -ERRNO_TO_ERROR(ENOMEM); + t->columns = calloc(desc->num_columns, sizeof(struct osl_column)); + if (!t->columns) + goto err; t->desc = desc; FOR_EACH_COLUMN(i, t->desc, cd) { enum osl_storage_type st = cd->storage_type; enum osl_storage_flags sf = cd->storage_flags; struct osl_column *col = &t->columns[i]; - ret = -E_BAD_STORAGE_TYPE; + ret = -E_OSL_BAD_STORAGE_TYPE; if (st != OSL_MAPPED_STORAGE && st != OSL_DISK_STORAGE && st != OSL_NO_STORAGE) goto err; - ret = -E_BAD_STORAGE_FLAGS; + ret = -E_OSL_BAD_STORAGE_FLAGS; if (st == OSL_DISK_STORAGE && sf & OSL_RBTREE) goto err; - ret = -E_BAD_STORAGE_SIZE; + ret = -E_OSL_BAD_STORAGE_SIZE; if (sf & OSL_FIXED_SIZE && !cd->data_size) goto err; switch (st) { @@ -475,10 +459,10 @@ int init_table_structure(const struct osl_table_description *desc, } } } - ret = -E_NO_UNIQUE_RBTREE_COLUMN; + ret = -E_OSL_NO_UNIQUE_RBTREE_COLUMN; if (t->num_disk_storage_columns && !have_disk_storage_name_column) goto err; - ret = -E_NO_RBTREE_COL; + ret = -E_OSL_NO_RBTREE_COL; if (!t->num_rbtrees) goto err; /* success */ @@ -503,7 +487,7 @@ err: * Read the index header, check for the paraslash magic string and the table version number. * Read all information stored in the index header into \a desc. * - * \return Positive on success, negative on errors. + * \return Standard. * * \sa struct osl_table_description, osl_create_table. */ @@ -517,27 +501,29 @@ int read_table_desc(struct osl_object *map, struct osl_table_description *desc) struct osl_column_description *cd; if (map->size < MIN_INDEX_HEADER_SIZE(1)) - return -E_SHORT_TABLE; + return -E_OSL_SHORT_TABLE; if (strncmp(buf + IDX_PARA_MAGIC, PARA_MAGIC, strlen(PARA_MAGIC))) - return -E_NO_MAGIC; + return -E_OSL_NO_MAGIC; version = read_u8(buf + IDX_VERSION); if (version < MIN_TABLE_VERSION || version > MAX_TABLE_VERSION) - return -E_VERSION_MISMATCH; + return -E_OSL_VERSION_MISMATCH; desc->flags = read_u8(buf + IDX_TABLE_FLAGS); desc->num_columns = read_u16(buf + IDX_NUM_COLUMNS); - DEBUG_LOG("%u columns\n", desc->num_columns); + INFO_LOG("%u columns\n", desc->num_columns); if (!desc->num_columns) - return -E_NO_COLUMNS; + return -E_OSL_NO_COLUMNS; header_size = read_u16(buf + IDX_HEADER_SIZE); if (map->size < header_size) - return -E_BAD_SIZE; - desc->column_descriptions = para_calloc(desc->num_columns - * sizeof(struct osl_column_description)); + return -E_OSL_BAD_SIZE; + desc->column_descriptions = calloc(desc->num_columns, + sizeof(struct osl_column_description)); + if (!desc->column_descriptions) + return -ERRNO_TO_ERROR(ENOMEM); offset = IDX_COLUMN_DESCRIPTIONS; FOR_EACH_COLUMN(i, desc, cd) { char *null_byte; - ret = -E_SHORT_TABLE; + ret = -E_OSL_SHORT_TABLE; if (map->size < offset + MIN_IDX_COLUMN_DESCRIPTION_SIZE) { ERROR_LOG("map size = %zu < %u = offset + min desc size\n", map->size, offset + MIN_IDX_COLUMN_DESCRIPTION_SIZE); @@ -549,14 +535,17 @@ int read_table_desc(struct osl_object *map, struct osl_table_description *desc) cd->data_size = read_u32(buf + offset + IDX_CD_DATA_SIZE); null_byte = memchr(buf + offset + IDX_CD_NAME, '\0', map->size - offset - IDX_CD_NAME); - ret = -E_INDEX_CORRUPTION; + ret = -E_OSL_INDEX_CORRUPTION; if (!null_byte) goto err; - cd->name = para_strdup(buf + offset + IDX_CD_NAME); + ret = -ERRNO_TO_ERROR(ENOMEM); + cd->name = strdup(buf + offset + IDX_CD_NAME); + if (!cd->name) + goto err; offset += index_column_description_size(cd->name); } if (offset != header_size) { - ret = -E_INDEX_CORRUPTION; + ret = -E_OSL_INDEX_CORRUPTION; ERROR_LOG("real header size = %u != %u = stored header size\n", offset, header_size); goto err; @@ -582,10 +571,10 @@ static int compare_table_descriptions(struct osl_table *t) ret = read_table_desc(&t->index_map, &desc); if (ret < 0) return ret; - ret = -E_BAD_TABLE_FLAGS; + ret = -E_OSL_BAD_TABLE_FLAGS; if (desc.flags != t->desc->flags) goto out; - ret = -E_BAD_COLUMN_NUM; + ret = -E_OSL_BAD_COLUMN_NUM; if (desc.num_columns > t->desc->num_columns) goto out; if (desc.num_columns < t->desc->num_columns) { @@ -606,26 +595,26 @@ static int compare_table_descriptions(struct osl_table *t) } FOR_EACH_COLUMN(i, t->desc, cd1) { cd2 = get_column_description(&desc, i); - ret = -E_BAD_STORAGE_TYPE; + ret = -E_OSL_BAD_STORAGE_TYPE; if (cd1->storage_type != cd2->storage_type) goto out; if (cd1->storage_type == OSL_NO_STORAGE) continue; - ret = -E_BAD_STORAGE_FLAGS; + ret = -E_OSL_BAD_STORAGE_FLAGS; if (cd1->storage_flags != cd2->storage_flags) { ERROR_LOG("sf1 = %u != %u = sf2\n", cd1->storage_flags, cd2->storage_flags); goto out; } - ret = -E_BAD_DATA_SIZE; + ret = -E_OSL_BAD_DATA_SIZE; if (cd1->storage_flags & OSL_FIXED_SIZE) if (cd1->data_size != cd2->data_size) goto out; - ret = -E_BAD_COLUMN_NAME; + ret = -E_OSL_BAD_COLUMN_NAME; if (strcmp(cd1->name, cd2->name)) goto out; } - DEBUG_LOG("table description of '%s' matches on-disk data, good\n", + INFO_LOG("table description of '%s' matches on-disk data, good\n", t->desc->name); ret = 1; out: @@ -645,7 +634,9 @@ static int create_table_index(struct osl_table *t) INFO_LOG("creating %zu byte index for table %s\n", size, t->desc->name); - buf = para_calloc(size); + buf = calloc(1, size); + if (!buf) + return -ERRNO_TO_ERROR(ENOMEM); sprintf(buf + IDX_PARA_MAGIC, "%s", PARA_MAGIC); write_u8(buf + IDX_TABLE_FLAGS, t->desc->flags); write_u8(buf + IDX_DIRTY_FLAG, 0); @@ -669,7 +660,10 @@ static int create_table_index(struct osl_table *t) } assert(offset = size); filename = index_filename(t->desc); - ret = para_write_file(filename, buf, size); + if (filename) + ret = write_file(filename, buf, size); + else + ret = -ERRNO_TO_ERROR(ENOMEM); free(buf); free(filename); return ret; @@ -682,7 +676,7 @@ static int create_table_index(struct osl_table *t) * * \return Standard. */ -int osl_create_table(const struct osl_table_description *desc) +__export int osl_create_table(const struct osl_table_description *desc) { const struct osl_column_description *cd; char *table_dir = NULL, *filename; @@ -701,14 +695,20 @@ int osl_create_table(const struct osl_table_description *desc) goto out; table_dir = make_message("%s/%s", desc->dir, desc->name); + ret = -ERRNO_TO_ERROR(ENOMEM); + if (!table_dir) + goto out; ret = para_mkdir(table_dir, 0777); if (ret < 0) goto out; } + ret = -ERRNO_TO_ERROR(ENOMEM); filename = column_filename(t, i); + if (!filename) + goto out; INFO_LOG("filename: %s\n", filename); if (cd->storage_type == OSL_MAPPED_STORAGE) { - ret = para_open(filename, O_RDWR | O_CREAT | O_EXCL, + ret = osl_open(filename, O_RDWR | O_CREAT | O_EXCL, 0644); free(filename); if (ret < 0) @@ -783,9 +783,9 @@ int unmap_table(struct osl_table *t, enum osl_close_flags flags) if (!t->num_mapped_columns) /* can this ever happen? */ return 1; - DEBUG_LOG("unmapping table '%s'\n", t->desc->name); + INFO_LOG("unmapping table '%s'\n", t->desc->name); if (!t->index_map.data) - return -E_NOT_MAPPED; + return -E_OSL_NOT_MAPPED; if (flags & OSL_MARK_CLEAN) mark_table_clean(t); ret = para_munmap(t->index_map.data, t->index_map.size); @@ -803,7 +803,10 @@ static int map_column(struct osl_table *t, unsigned col_num) { struct stat statbuf; char *filename = column_filename(t, col_num); - int ret = -E_STAT; + int ret = -E_OSL_STAT; + + if (!filename) + return -ERRNO_TO_ERROR(ENOMEM); if (stat(filename, &statbuf) < 0) { free(filename); return ret; @@ -840,9 +843,11 @@ int map_table(struct osl_table *t, enum map_table_flags flags) if (!t->num_mapped_columns) return 0; if (t->index_map.data) - return -E_ALREADY_MAPPED; + return -E_OSL_ALREADY_MAPPED; filename = index_filename(t->desc); - DEBUG_LOG("mapping table '%s' (index: %s)\n", t->desc->name, filename); + if (!filename) + return -ERRNO_TO_ERROR(ENOMEM); + INFO_LOG("mapping table '%s' (index: %s)\n", t->desc->name, filename); ret = mmap_full_file(filename, flags & MAP_TBL_FL_MAP_RDONLY? O_RDONLY : O_RDWR, &t->index_map.data, &t->index_map.size, NULL); free(filename); @@ -853,7 +858,7 @@ int map_table(struct osl_table *t, enum map_table_flags flags) if (ret < 0) goto err; } - ret = -E_BUSY; + ret = -E_OSL_BUSY; if (!(flags & MAP_TBL_FL_IGNORE_DIRTY)) { if (table_is_dirty(t)) { ERROR_LOG("%s is dirty\n", t->desc->name); @@ -893,8 +898,7 @@ err: /* unmap what is already mapped */ * It is considered an error if \a col_num does not refer to a column * of storage type \p OSL_MAPPED_STORAGE. * - * \return Positive on success, negative on errors. Possible errors include: - * \p E_BAD_ROW_NUM, \p E_INVALID_OBJECT. + * \return Standard. * * \sa osl_storage_type. */ @@ -908,7 +912,7 @@ int get_mapped_object(const struct osl_table *t, unsigned col_num, int ret; if (t->num_rows <= row_num) - return -E_BAD_ROW_NUM; + return -E_OSL_BAD_ROW_NUM; ret = get_cell_index(t, row_num, col_num, &cell_index); if (ret < 0) return ret; @@ -919,7 +923,7 @@ int get_mapped_object(const struct osl_table *t, unsigned col_num, if (read_u8(header) == 0xff) { ERROR_LOG("col %u, size %zu, offset %u\n", col_num, obj->size, offset); - return -E_INVALID_OBJECT; + return -E_OSL_INVALID_OBJECT; } return 1; } @@ -962,7 +966,7 @@ static int search_rbtree(const struct osl_object *obj, *result = parent; if (rb_link) *rb_link = new; - return -E_RB_KEY_NOT_FOUND; + return -E_OSL_RB_KEY_NOT_FOUND; } static int insert_rbtree(struct osl_table *t, unsigned col_num, @@ -974,7 +978,7 @@ static int insert_rbtree(struct osl_table *t, unsigned col_num, int ret = search_rbtree(obj, t, col_num, &parent, &rb_link); if (ret > 0) - return -E_RB_KEY_EXISTS; + return -E_OSL_RB_KEY_EXISTS; rbtree_num = t->columns[col_num].rbtree_num; n = get_rb_node_pointer(row, rbtree_num); rb_link_node(n, parent, rb_link); @@ -1018,6 +1022,8 @@ static int add_row_to_rbtrees(struct osl_table *t, uint32_t row_num, struct osl_row *row = allocate_row(t->num_rbtrees); const struct osl_column_description *cd; + if (!row) + return -ERRNO_TO_ERROR(ENOMEM); row->num = row_num; row->volatile_objects = volatile_objs; FOR_EACH_RBTREE_COLUMN(i, t, cd) { @@ -1115,17 +1121,17 @@ void clear_rbtrees(struct osl_table *t) * passed to this function in order to flush all changes to the file system and * to free the resources that were allocated by osl_open_table(). * - * \return Positive on success, negative on errors. Possible errors: \p E_BAD_TABLE, - * errors returned by unmap_table(). + * \return Standard. * * \sa osl_open_table(), unmap_table(). */ -int osl_close_table(struct osl_table *t, enum osl_close_flags flags) +__export int osl_close_table(struct osl_table *t, enum osl_close_flags flags) { int ret; if (!t) - return -E_BAD_TABLE; + return -E_OSL_BAD_TABLE; + NOTICE_LOG("closing table %s\n", t->desc->name); free_volatile_objects(t, flags); clear_rbtrees(t); ret = unmap_table(t, flags); @@ -1172,7 +1178,7 @@ int row_is_invalid(struct osl_table *t, uint32_t row_num) * This function marks each mapped object in the index entry of \a row as * invalid. * - * \return Positive on success, negative on errors. + * \return Standard. */ int mark_row_invalid(struct osl_table *t, uint32_t row_num) { @@ -1191,7 +1197,7 @@ int mark_row_invalid(struct osl_table *t, uint32_t row_num) * * \param t The table containing the rbtrees to be initialized. * - * \return Positive on success, negative on errors. + * \return Standard. */ int init_rbtrees(struct osl_table *t) { @@ -1231,21 +1237,25 @@ int init_rbtrees(struct osl_table *t) * * \return Standard. */ -int osl_open_table(const struct osl_table_description *table_desc, +__export int osl_open_table(const struct osl_table_description *table_desc, struct osl_table **result) { int i, ret; struct osl_table *t; const struct osl_column_description *cd; - INFO_LOG("opening table %s\n", table_desc->name); + NOTICE_LOG("opening table %s\n", table_desc->name); ret = init_table_structure(table_desc, &t); if (ret < 0) return ret; FOR_EACH_DISK_STORAGE_COLUMN(i, t, cd) { - /* check if directory exists */ - char *dirname = column_filename(t, i); struct stat statbuf; + char *dirname = column_filename(t, i); + + ret = -ERRNO_TO_ERROR(ENOMEM); + if (!dirname) + goto err; + /* check if directory exists */ ret = stat(dirname, &statbuf); free(dirname); if (ret < 0) { @@ -1283,6 +1293,8 @@ static int create_disk_storage_object_dir(const struct osl_table *t, if (!(t->desc->flags & OSL_LARGE_TABLE)) return 1; dirname = disk_storage_dirname(t, col_num, ds_name); + if (!dirname) + return -ERRNO_TO_ERROR(ENOMEM); ret = para_mkdir(dirname, 0777); free(dirname); if (ret < 0 && !is_errno(-ret, EEXIST)) @@ -1300,7 +1312,9 @@ static int write_disk_storage_file(const struct osl_table *t, unsigned col_num, if (ret < 0) return ret; filename = disk_storage_path(t, col_num, ds_name); - ret = para_write_file(filename, obj->data, obj->size); + if (!filename) + return -ERRNO_TO_ERROR(ENOMEM); + ret = write_file(filename, obj->data, obj->size); free(filename); return ret; } @@ -1312,7 +1326,8 @@ static int append_map_file(const struct osl_table *t, unsigned col_num, int ret; char header = 0; /* zero means valid object */ -// DEBUG_LOG("appending %zu + 1 byte\n", obj->size); + if (!filename) + return -ERRNO_TO_ERROR(ENOMEM); ret = append_file(filename, &header, 1, obj->data, obj->size, new_size); free(filename); @@ -1327,6 +1342,8 @@ static int append_row_index(const struct osl_table *t, char *row_index) if (!t->num_mapped_columns) return 1; filename = index_filename(t->desc); + if (!filename) + return -ERRNO_TO_ERROR(ENOMEM); ret = append_file(filename, NULL, 0, row_index, t->row_index_size, NULL); free(filename); @@ -1341,8 +1358,7 @@ static int append_row_index(const struct osl_table *t, char *row_index) * * Truncate the regular file named by \a path by \a size bytes. * - * \return Positive on success, negative on errors. Possible errors include: \p - * E_STAT, \p E_BAD_SIZE, \p E_TRUNC. + * \return Standard. * * \sa truncate(2) */ @@ -1351,13 +1367,13 @@ int para_truncate(const char *path, off_t size) int ret; struct stat statbuf; - ret = -E_STAT; + ret = -E_OSL_STAT; if (stat(path, &statbuf) < 0) goto out; - ret = -E_BAD_SIZE; + ret = -E_OSL_BAD_SIZE; if (statbuf.st_size < size) goto out; - ret = -E_TRUNC; + ret = -E_OSL_TRUNC; if (truncate(path, statbuf.st_size - size) < 0) goto out; ret = 1; @@ -1368,8 +1384,12 @@ out: static int truncate_mapped_file(const struct osl_table *t, unsigned col_num, off_t size) { + int ret; char *filename = column_filename(t, col_num); - int ret = para_truncate(filename, size); + + if (!filename) + return -ERRNO_TO_ERROR(ENOMEM); + ret = para_truncate(filename, size); free(filename); return ret; } @@ -1378,14 +1398,20 @@ static int delete_disk_storage_file(const struct osl_table *t, unsigned col_num, const char *ds_name) { char *dirname, *filename = disk_storage_path(t, col_num, ds_name); - int ret = unlink(filename), err = errno; + int ret, err; + if (!filename) + return -ERRNO_TO_ERROR(ENOMEM); + ret = unlink(filename); + err = errno; free(filename); if (ret < 0) return -ERRNO_TO_ERROR(err); if (!(t->desc->flags & OSL_LARGE_TABLE)) return 1; dirname = disk_storage_dirname(t, col_num, ds_name); + if (!dirname) + return -ERRNO_TO_ERROR(ENOMEM); rmdir(dirname); free(dirname); return 1; @@ -1410,13 +1436,11 @@ static int delete_disk_storage_file(const struct osl_table *t, unsigned col_num, * rbtree if this object is equal to an object already contained in that column * (i.e. the compare function for the column's rbtree returns zero). * - * Possible errors include: \p E_RB_KEY_EXISTS, \p E_BAD_DATA_SIZE. - * - * \return Positive on success, negative on errors. + * \return Standard. * * \sa struct osl_table_description, osl_compare_func, osl_add_row(). */ -int osl_add_and_get_row(struct osl_table *t, struct osl_object *objects, +__export int osl_add_and_get_row(struct osl_table *t, struct osl_object *objects, struct osl_row **row) { int i, ret; @@ -1427,11 +1451,23 @@ int osl_add_and_get_row(struct osl_table *t, struct osl_object *objects, const struct osl_column_description *cd; if (!t) - return -E_BAD_TABLE; - rb_parents = para_malloc(t->num_rbtrees * sizeof(struct rn_node*)); - rb_links = para_malloc(t->num_rbtrees * sizeof(struct rn_node**)); - if (t->num_mapped_columns) - new_row_index = para_malloc(t->row_index_size); + return -E_OSL_BAD_TABLE; + rb_parents = malloc(t->num_rbtrees * sizeof(struct rn_node*)); + if (!rb_parents) + return -ERRNO_TO_ERROR(ENOMEM); + rb_links = malloc(t->num_rbtrees * sizeof(struct rn_node**)); + if (!rb_links) { + free(rb_parents); + return -ERRNO_TO_ERROR(ENOMEM); + } + if (t->num_mapped_columns) { + new_row_index = malloc(t->row_index_size); + if (!new_row_index) { + free(rb_links); + free(rb_parents); + return -ERRNO_TO_ERROR(ENOMEM); + } + } /* pass 1: sanity checks */ // DEBUG_LOG("sanity tests: %p:%p\n", objects[0].data, // objects[1].data); @@ -1439,14 +1475,14 @@ int osl_add_and_get_row(struct osl_table *t, struct osl_object *objects, enum osl_storage_type st = cd->storage_type; enum osl_storage_flags sf = cd->storage_flags; -// ret = -E_NULL_OBJECT; +// ret = -E_OSL_NULL_OBJECT; // if (!objects[i]) // goto out; if (st == OSL_DISK_STORAGE) continue; if (sf & OSL_RBTREE) { unsigned rbtree_num = t->columns[i].rbtree_num; - ret = -E_RB_KEY_EXISTS; + ret = -E_OSL_RB_KEY_EXISTS; // DEBUG_LOG("checking whether %p exists\n", // objects[i].data); if (search_rbtree(objects + i, t, i, @@ -1457,14 +1493,18 @@ int osl_add_and_get_row(struct osl_table *t, struct osl_object *objects, if (sf & OSL_FIXED_SIZE) { // DEBUG_LOG("fixed size. need: %zu, have: %d\n", // objects[i].size, cd->data_size); - ret = -E_BAD_DATA_SIZE; + ret = -E_OSL_BAD_DATA_SIZE; if (objects[i].size != cd->data_size) goto out; } } - if (t->num_disk_storage_columns) + if (t->num_disk_storage_columns) { ds_name = disk_storage_name_of_object(t, &objects[t->disk_storage_name_column]); + ret = -ERRNO_TO_ERROR(ENOMEM); + if (!ds_name) + goto out; + } ret = unmap_table(t, OSL_MARK_CLEAN); if (ret < 0) goto out; @@ -1497,14 +1537,18 @@ int osl_add_and_get_row(struct osl_table *t, struct osl_object *objects, ret = map_table(t, MAP_TBL_FL_VERIFY_INDEX); if (ret < 0) { /* truncate index and rollback changes */ char *filename = index_filename(t->desc); - para_truncate(filename, t->row_index_size); + if (filename) + para_truncate(filename, t->row_index_size); free(filename); goto rollback; } /* pass 3: add entry to rbtrees */ if (t->num_volatile_columns) { - volatile_objs = para_calloc(t->num_volatile_columns - * sizeof(struct osl_object)); + ret = -ERRNO_TO_ERROR(ENOMEM); + volatile_objs = calloc(t->num_volatile_columns, + sizeof(struct osl_object)); + if (!volatile_objs) + goto out; FOR_EACH_VOLATILE_COLUMN(i, t, cd) volatile_objs[t->columns[i].volatile_num] = objects[i]; } @@ -1548,7 +1592,7 @@ out: * * This is equivalent to osl_add_and_get_row(t, objects, NULL). */ -int osl_add_row(struct osl_table *t, struct osl_object *objects) +__export int osl_add_row(struct osl_table *t, struct osl_object *objects) { return osl_add_and_get_row(t, objects, NULL); } @@ -1565,22 +1609,21 @@ int osl_add_row(struct osl_table *t, struct osl_object *objects) * or \p OSL_NO_STORAGE, i.e. no disk storage objects may be retrieved by this * function. * - * \return Positive if object was found, negative on errors. Possible errors - * include: \p E_BAD_TABLE, \p E_BAD_STORAGE_TYPE. + * \return Standard. * * \sa osl_storage_type, osl_open_disk_object(). */ -int osl_get_object(const struct osl_table *t, const struct osl_row *r, +__export int osl_get_object(const struct osl_table *t, const struct osl_row *r, unsigned col_num, struct osl_object *object) { const struct osl_column_description *cd; if (!t) - return -E_BAD_TABLE; + return -E_OSL_BAD_TABLE; cd = get_column_description(t->desc, col_num); /* col must not be disk storage */ if (cd->storage_type == OSL_DISK_STORAGE) - return -E_BAD_STORAGE_TYPE; + return -E_OSL_BAD_STORAGE_TYPE; if (cd->storage_type == OSL_MAPPED_STORAGE) return get_mapped_object(t, col_num, r->num, object); /* volatile */ @@ -1614,17 +1657,16 @@ static int mark_mapped_object_invalid(const struct osl_table *t, * data is merely marked invalid and may be pruned from time to time by * para_fsck. * - * \return Positive on success, negative on errors. Possible errors include: - * \p E_BAD_TABLE, errors returned by osl_get_object(). + * \return Standard. */ -int osl_del_row(struct osl_table *t, struct osl_row *row) +__export int osl_del_row(struct osl_table *t, struct osl_row *row) { struct osl_row *r = row; int i, ret; const struct osl_column_description *cd; if (!t) - return -E_BAD_TABLE; + return -E_OSL_BAD_TABLE; INFO_LOG("deleting row %p\n", row); if (t->num_disk_storage_columns) { @@ -1666,9 +1708,9 @@ static int check_rbtree_col(const struct osl_table *t, unsigned col_num, struct osl_column **col) { if (!t) - return -E_BAD_TABLE; + return -E_OSL_BAD_TABLE; if (!(get_column_description(t->desc, col_num)->storage_flags & OSL_RBTREE)) - return -E_BAD_STORAGE_FLAGS; + return -E_OSL_BAD_STORAGE_FLAGS; *col = t->columns + col_num; return 1; } @@ -1684,14 +1726,11 @@ static int check_rbtree_col(const struct osl_table *t, unsigned col_num, * Lookup \a obj in \a t and return the row containing \a obj. The column * specified by \a col_num must have an associated rbtree. * - * \return Positive on success, negative on errors. If an error occurred, \a - * result is set to \p NULL. Possible errors include: \p E_BAD_TABLE, \p - * E_BAD_STORAGE_FLAGS, errors returned by get_mapped_object(), \p - * E_RB_KEY_NOT_FOUND. + * \return Standard. * * \sa osl_storage_flags */ -int osl_get_row(const struct osl_table *t, unsigned col_num, +__export int osl_get_row(const struct osl_table *t, unsigned col_num, const struct osl_object *obj, struct osl_row **result) { int ret; @@ -1711,7 +1750,7 @@ int osl_get_row(const struct osl_table *t, unsigned col_num, return 1; } -static int rbtree_loop(struct osl_column *col, void *private_data, +static int rbtree_loop(struct osl_column *col, void *private_data, osl_rbtree_loop_func *func) { struct rb_node *n, *tmp; @@ -1721,14 +1760,13 @@ static int rbtree_loop(struct osl_column *col, void *private_data, n; n = tmp, tmp = tmp? rb_next(tmp) : NULL) { struct osl_row *r = get_row_pointer(n, col->rbtree_num); - int ret = func(r, private_data); - if (ret < 0) - return ret; + if (func(r, private_data) < 0) + return -E_OSL_LOOP; } return 1; } -static int rbtree_loop_reverse(struct osl_column *col, void *private_data, +static int rbtree_loop_reverse(struct osl_column *col, void *private_data, osl_rbtree_loop_func *func) { struct rb_node *n, *tmp; @@ -1738,9 +1776,8 @@ static int rbtree_loop_reverse(struct osl_column *col, void *private_data, n; n = tmp, tmp = tmp? rb_prev(tmp) : NULL) { struct osl_row *r = get_row_pointer(n, col->rbtree_num); - int ret = func(r, private_data); - if (ret < 0) - return ret; + if (func(r, private_data) < 0) + return -E_OSL_LOOP; } return 1; } @@ -1763,13 +1800,12 @@ static int rbtree_loop_reverse(struct osl_column *col, void *private_data, * value, or if all nodes of the tree have been visited. * * - * \return Positive on success, negative on errors. If the termination of the - * loop was caused by \a func returning a negative value, this value is - * returned. + * \return Standard. If the termination of the loop was caused by \a func + * returning a negative value, \p -E_OSL_LOOP is returned. * * \sa osl_storage_flags, osl_rbtree_loop_reverse(), osl_compare_func. */ -int osl_rbtree_loop(const struct osl_table *t, unsigned col_num, +__export int osl_rbtree_loop(const struct osl_table *t, unsigned col_num, void *private_data, osl_rbtree_loop_func *func) { struct osl_column *col; @@ -1795,7 +1831,7 @@ int osl_rbtree_loop(const struct osl_table *t, unsigned col_num, * * \sa osl_rbtree_loop(). */ -int osl_rbtree_loop_reverse(const struct osl_table *t, unsigned col_num, +__export int osl_rbtree_loop_reverse(const struct osl_table *t, unsigned col_num, void *private_data, osl_rbtree_loop_func *func) { struct osl_column *col; @@ -1821,6 +1857,10 @@ static int rename_disk_storage_objects(struct osl_table *t, return 1; /* object did not change */ old_ds_name = disk_storage_name_of_object(t, old_obj); new_ds_name = disk_storage_name_of_object(t, new_obj); + ret = -ERRNO_TO_ERROR(ENOMEM); + if (!old_ds_name || ! new_ds_name) + goto out; + FOR_EACH_DISK_STORAGE_COLUMN(i, t, cd) { char *old_filename, *new_filename; ret = create_disk_storage_object_dir(t, i, new_ds_name); @@ -1828,7 +1868,10 @@ static int rename_disk_storage_objects(struct osl_table *t, goto out; old_filename = disk_storage_path(t, i, old_ds_name); new_filename = disk_storage_path(t, i, new_ds_name); - ret = para_rename(old_filename, new_filename); + if (!old_filename || !new_filename) + ret = -ERRNO_TO_ERROR(ENOMEM); + else + ret = para_rename(old_filename, new_filename); free(old_filename); free(new_filename); if (ret < 0) @@ -1861,7 +1904,7 @@ out: * * \return Standard */ -int osl_update_object(struct osl_table *t, const struct osl_row *r, +__export int osl_update_object(struct osl_table *t, const struct osl_row *r, unsigned col_num, struct osl_object *obj) { struct osl_column *col; @@ -1869,17 +1912,17 @@ int osl_update_object(struct osl_table *t, const struct osl_row *r, int ret; if (!t) - return -E_BAD_TABLE; + return -E_OSL_BAD_TABLE; col = &t->columns[col_num]; cd = get_column_description(t->desc, col_num); DEBUG_LOG("updating column %u of %s\n", col_num, t->desc->name); if (cd->storage_flags & OSL_RBTREE) { if (search_rbtree(obj, t, col_num, NULL, NULL) > 0) - return -E_RB_KEY_EXISTS; + return -E_OSL_RB_KEY_EXISTS; } if (cd->storage_flags & OSL_FIXED_SIZE) { if (obj->size != cd->data_size) - return -E_BAD_DATA_SIZE; + return -E_OSL_BAD_DATA_SIZE; } remove_rb_node(t, col_num, r); if (cd->storage_type == OSL_NO_STORAGE) { /* TODO: If fixed size, reuse object? */ @@ -1957,12 +2000,11 @@ int osl_update_object(struct osl_table *t, const struct osl_row *r, * retrieve one of its containing objects. Afterwards, osl_close_disk_object() * must be called in order to deallocate the resources. * - * \return Positive on success, negative on errors. Possible errors include: - * \p E_BAD_TABLE, \p E_BAD_STORAGE_TYPE, errors returned by osl_get_object(). + * \return Standard. * * \sa osl_get_object(), osl_storage_type, osl_close_disk_object(). */ -int osl_open_disk_object(const struct osl_table *t, const struct osl_row *r, +__export int osl_open_disk_object(const struct osl_table *t, const struct osl_row *r, unsigned col_num, struct osl_object *obj) { const struct osl_column_description *cd; @@ -1970,16 +2012,18 @@ int osl_open_disk_object(const struct osl_table *t, const struct osl_row *r, int ret; if (!t) - return -E_BAD_TABLE; + return -E_OSL_BAD_TABLE; cd = get_column_description(t->desc, col_num); if (cd->storage_type != OSL_DISK_STORAGE) - return -E_BAD_STORAGE_TYPE; + return -E_OSL_BAD_STORAGE_TYPE; ret = disk_storage_name_of_row(t, r, &ds_name); if (ret < 0) return ret; filename = disk_storage_path(t, col_num, ds_name); free(ds_name); + if (!filename) + return -ERRNO_TO_ERROR(ENOMEM); DEBUG_LOG("filename: %s\n", filename); ret = mmap_full_file(filename, O_RDONLY, &obj->data, &obj->size, NULL); free(filename); @@ -1995,7 +2039,7 @@ int osl_open_disk_object(const struct osl_table *t, const struct osl_row *r, * * \sa para_munmap(). */ -int osl_close_disk_object(struct osl_object *obj) +__export int osl_close_disk_object(struct osl_object *obj) { return para_munmap(obj->data, obj->size); } @@ -2008,12 +2052,12 @@ int osl_close_disk_object(struct osl_object *obj) * * The number of rows returned via \a num_rows excluding any invalid rows. * - * \return Positive on success, \p -E_BAD_TABLE if \a t is \p NULL. + * \return Positive on success, \p -E_OSL_BAD_TABLE if \a t is \p NULL. */ -int osl_get_num_rows(const struct osl_table *t, unsigned *num_rows) +__export int osl_get_num_rows(const struct osl_table *t, unsigned *num_rows) { if (!t) - return -E_BAD_TABLE; + return -E_OSL_BAD_TABLE; assert(t->num_rows >= t->num_invalid_rows); *num_rows = t->num_rows - t->num_invalid_rows; return 1; @@ -2031,11 +2075,11 @@ int osl_get_num_rows(const struct osl_table *t, unsigned *num_rows) * determined by an in-order tree walk of the rbtree associated with column * number \a col_num of \a table. * - * \return Positive on success, negative on errors. + * \return Standard. * * \sa osl_get_nth_row(). */ -int osl_get_rank(const struct osl_table *t, struct osl_row *r, +__export int osl_get_rank(const struct osl_table *t, struct osl_row *r, unsigned col_num, unsigned *rank) { struct osl_object obj; @@ -2053,7 +2097,7 @@ int osl_get_rank(const struct osl_table *t, struct osl_row *r, return ret; ret = rb_rank(node, rank); if (ret < 0) - return -E_BAD_ROW; + return -E_OSL_BAD_ROW; return 1; } @@ -2071,13 +2115,12 @@ int osl_get_rank(const struct osl_table *t, struct osl_row *r, * \a col_num is not a rbtree column, or if \a n is larger than the * number of rows in the table. * - * \return Positive on success, negative on errors. Possible errors: - * \p E_BAD_TABLE, \p E_BAD_STORAGE_FLAGS, \p E_RB_KEY_NOT_FOUND. + * \return Standard. * * \sa osl_storage_flags, osl_compare_func, osl_get_row(), * osl_rbtree_last_row(), osl_rbtree_first_row(), osl_get_rank(). */ -int osl_get_nth_row(const struct osl_table *t, unsigned col_num, +__export int osl_get_nth_row(const struct osl_table *t, unsigned col_num, unsigned n, struct osl_row **result) { struct osl_column *col; @@ -2086,18 +2129,18 @@ int osl_get_nth_row(const struct osl_table *t, unsigned col_num, int ret; if (n == 0) - return -E_RB_KEY_NOT_FOUND; + return -E_OSL_RB_KEY_NOT_FOUND; ret = osl_get_num_rows(t, &num_rows); if (ret < 0) return ret; if (n > num_rows) - return -E_RB_KEY_NOT_FOUND; + return -E_OSL_RB_KEY_NOT_FOUND; ret = check_rbtree_col(t, col_num, &col); if (ret < 0) return ret; node = rb_nth(col->rbtree.rb_node, n); if (!node) - return -E_RB_KEY_NOT_FOUND; + return -E_OSL_RB_KEY_NOT_FOUND; *result = get_row_pointer(node, col->rbtree_num); return 1; } @@ -2114,11 +2157,11 @@ int osl_get_nth_row(const struct osl_table *t, unsigned col_num, * returned. It is an error if \a col_num refers to a column without an * associated rbtree. * - * \return Positive on success, negative on errors. + * \return Standard. * * \sa osl_get_nth_row(), osl_rbtree_last_row(). */ -int osl_rbtree_first_row(const struct osl_table *t, unsigned col_num, +__export int osl_rbtree_first_row(const struct osl_table *t, unsigned col_num, struct osl_row **result) { return osl_get_nth_row(t, col_num, 1, result); @@ -2135,11 +2178,11 @@ int osl_rbtree_first_row(const struct osl_table *t, unsigned col_num, * is that the row containing the greatest rather than the smallest object is * returned. * - * \return Positive on success, negative on errors. + * \return Standard. * * \sa osl_get_nth_row(), osl_rbtree_first_row(). */ -int osl_rbtree_last_row(const struct osl_table *t, unsigned col_num, +__export int osl_rbtree_last_row(const struct osl_table *t, unsigned col_num, struct osl_row **result) { unsigned num_rows;