diff --git a/src/obidms.c b/src/obidms.c index 2b7a966..a0c1d9f 100644 --- a/src/obidms.c +++ b/src/obidms.c @@ -14,6 +14,10 @@ #include "obidms.h" #include "obierrno.h" +#include "obidebug.h" +#include "obidmscolumn.h" + +#define DEBUG_LEVEL 0 /************************************************************************** @@ -148,6 +152,7 @@ OBIDMS_p obi_open_dms(const char* dms_name) directory = opendir(directory_name); if (directory == NULL) { + obidebug(1, "Can't open DMS"); switch (errno) { case ENOENT: @@ -206,6 +211,49 @@ OBIDMS_p obi_dms(const char* dms_name) } +int obi_list_columns(OBIDMS_p dms) +{ + DIR *d; + struct dirent *dir; + char* dir_name; + char* extension; + OBIType_t data_type; + obiversion_t latest_version; + + d = dms->directory; + + dir = readdir(d); + + fprintf(stderr, "Column name\tData type\tLatest version"); + + while (dir != NULL) + { + dir_name = strdup(dir->d_name); + if (dir_name == NULL) + { + obidebug(1, "\nError strdup-ing a directory name"); + return -1; + } + + dir_name = strtok(dir_name, "."); + extension = strtok(NULL, "."); + + if ((extension != NULL) && (strcmp("obicol", extension) == 0)) + // Found a column directory + { + data_type = obi_column_get_data_type_from_name(dms, dir_name); + latest_version = obi_column_get_latest_version_from_name(dms, dir_name); + fprintf(stderr, "\n%s\t%d\t%d", dir_name, data_type, latest_version); + } + dir = readdir(d); + } + + rewinddir(d); + + return(0); +} + + int obi_close_dms(OBIDMS_p dms) { if (dms != NULL) diff --git a/src/obidms.h b/src/obidms.h index aa001df..74397e5 100644 --- a/src/obidms.h +++ b/src/obidms.h @@ -126,6 +126,23 @@ OBIDMS_p obi_open_dms(const char *dms_name); OBIDMS_p obi_dms(const char *dms_name); +/** + * @brief Lists all the column directories in the OBIDMS, their data type and + * their latest version. + * + * @param dms a pointer as returned by obi_create_dms() or obi_open_dms(). + * + * @return an integer value indicating the success of the operation. + * + * @retvalue 0 on success + * @retvalue -1 on failure and the `obi_errno` variable is set. + * + * @since July 2015 + * @author Celine Mercier (celine.mercier@metabarcoding.org) + */ +int obi_list_columns(OBIDMS_p dms); + + /** * @brief Closes an opened OBITools Data Management instance (OBIDMS). * diff --git a/src/obidmscolumn.c b/src/obidmscolumn.c index 6e0f94a..648a937 100644 --- a/src/obidmscolumn.c +++ b/src/obidmscolumn.c @@ -3,7 +3,7 @@ ****************************************************************************/ /** - * @file OBIDMS_column.h + * @file obidmscolumn.c * @author Celine Mercier * @date 22 May 2015 * @brief Functions for the shared elements of all the OBIColumn structures. @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -27,6 +28,11 @@ #include "obidebug.h" #include "obilittlebigman.h" +#include "obidmscolumn_int.h" + + +#define DEBUG_LEVEL 0 + /************************************************************************** * @@ -115,13 +121,28 @@ static obiversion_t obi_get_new_version_number(OBIDMS_column_directory_p column_ static int create_version_file(OBIDMS_column_directory_p column_directory); +/** + * @brief Internal function setting the elements names of the lines of a + * column in the header of the OBIDMS column structure. + * + * @param column a pointer as returned by obi_create_column() + * @param elements_names the names of the elements with ';' as separator + * + * @return 0 if the operation was successfully completed + * @retvalue -1 if an error occurred + * + * @since July 2015 + * @author Celine Mercier (celine.mercier@metabarcoding.org) + */ +int obi_column_set_elements_names(OBIDMS_column_p column, const char* elements_names); + + /************************************************************************ * * D E F I N I T I O N O F T H E P R I V A T E F U N C T I O N S * ************************************************************************/ -#define DEBUG_LEVEL 0 static char *build_column_file_name(const char *column_name, obiversion_t version_number) { @@ -423,6 +444,16 @@ static int create_version_file(OBIDMS_column_directory_p column_directory) } +int obi_column_set_elements_names(OBIDMS_column_p column, const char* elements_names) +{ + (column->header)->elements_names = malloc(strlen(elements_names)*sizeof(char) + 1); + if ((column->header)->elements_names == NULL) + return -1; + strcpy((column->header)->elements_names, elements_names); + return 0; +} + + /********************************************************************** * * D E F I N I T I O N O F T H E P U B L I C F U N C T I O N S @@ -521,6 +552,32 @@ obiversion_t obi_get_latest_version_number(OBIDMS_column_directory_p column_dire } +obiversion_t obi_column_get_latest_version_from_name(OBIDMS_p dms, const char* column_name) +{ + OBIDMS_column_directory_p column_directory; + obiversion_t latest_version; + + // Get the column directory structure associated to the column + column_directory = obi_open_column_directory(dms, column_name); + if (column_directory == NULL) + { + obidebug(1, "\nProblem opening column directory"); + return -1; + } + + // Get the latest version number + latest_version = obi_get_latest_version_number(column_directory); + if (latest_version < 0) + { + obidebug(1, "\nProblem getting the latest version number"); + obi_close_column_directory(column_directory); + return -1; + } + + return latest_version; +} + + size_t obi_get_platform_header_size() { return getpagesize() * 1; @@ -547,6 +604,8 @@ OBIDMS_column_p obi_create_column(OBIDMS_p dms, new_column = NULL; + // TODO check that informations are not NULL/invalid + // Get the column directory structure associated to the column column_directory = obi_column_directory(dms, column_name); if (column_directory == NULL) @@ -673,8 +732,7 @@ OBIDMS_column_p obi_create_column(OBIDMS_p dms, header->version = version_number; header->comments[0] = 0x0; - header->elements_names = malloc(strlen(elements_names)*sizeof(char) + 1); - strcpy(header->elements_names, elements_names); + obi_column_set_elements_names(new_column, elements_names); strncpy(header->name, column_name, OBIDMS_MAX_COLNAME); @@ -683,3 +741,316 @@ OBIDMS_column_p obi_create_column(OBIDMS_p dms, return new_column; } + + +OBIDMS_column_p obi_open_column(OBIDMS_p dms, const char* column_name, obiversion_t version_number) +{ + OBIDMS_column_p column; + OBIDMS_column_directory_p column_directory; + char* column_file_name; + int column_file_descriptor; + int column_dir_file_descriptor; + size_t header_size; + size_t data_size; + + column = NULL; + + // Get the column directory structure associated to the column + column_directory = obi_open_column_directory(dms, column_name); + if (column_directory == NULL) + { + obidebug(1, "\nProblem opening column directory"); + return NULL; + } + + // Get the file descriptor associated to the column directory + column_dir_file_descriptor = dirfd(column_directory->directory); + if (column_dir_file_descriptor < 0) + { + obidebug(1, "\nProblem opening column directory"); + obi_set_errno(OBICOLDIR_UNKNOWN_ERROR); + obi_close_column_directory(column_directory); + return NULL; + } + + // Calculate the header size + header_size = obi_get_platform_header_size(); + + // Get the latest version number if it has the value -1 (not given by user) + if (version_number == -1) + { + version_number = obi_get_latest_version_number(column_directory); + if (version_number < 0) + { + obidebug(1, "\nProblem getting the latest version number"); + obi_close_column_directory(column_directory); + close(column_dir_file_descriptor); + return NULL; + } + } + + // Get the column file name + column_file_name = build_column_file_name(column_name, version_number); + if (column_file_name == NULL) + { + obidebug(1, "Problem building column file name"); + obi_close_column_directory(column_directory); + close(column_dir_file_descriptor); + return NULL; + } + + // Open the column file, ALWAYS READ-ONLY + column_file_descriptor = openat(column_dir_file_descriptor, column_file_name, O_RDONLY); + if (column_file_descriptor < 0) + { + obidebug(1, "\nCan't open column file"); + obi_set_errno(OBICOL_UNKNOWN_ERROR); + obi_close_column_directory(column_directory); + close(column_dir_file_descriptor); + free(column_file_name); + return NULL; + } + + // Allocate the memory for the column structure + column = (OBIDMS_column_p) malloc(sizeof(OBIDMS_column_t)); + if (column == NULL) + { + obi_set_errno(OBICOL_UNKNOWN_ERROR); + obi_close_column_directory(column_directory); + close(column_dir_file_descriptor); + close(column_file_descriptor); + free(column_file_name); + return NULL; + } + + // Fill the column structure + column->dms = dms; + column->column_directory = column_directory; + column->header = mmap(NULL, + header_size, + PROT_READ, + MAP_SHARED, + column_file_descriptor, + 0 + ); + + if (column->header == MAP_FAILED) + { + obi_set_errno(OBICOL_UNKNOWN_ERROR); + obi_close_column_directory(column_directory); + close(column_dir_file_descriptor); + close(column_file_descriptor); + free(column_file_name); + free(column); + return NULL; + } + + // Check endianness? + + // Compute data size from the informations in the header + data_size = ((column->header)->line_count) * sizeof((column->header)->data_type); // TODO line_count for tests, change to lines_used later + + column->data = mmap(NULL, + data_size, + PROT_READ, + MAP_SHARED, + column_file_descriptor, + header_size + ); + + if (column->data == MAP_FAILED) + { + munmap(column->header, header_size); + obi_set_errno(OBICOL_UNKNOWN_ERROR); + obi_close_column_directory(column_directory); + close(column_dir_file_descriptor); + close(column_file_descriptor); + free(column_file_name); + free(column); + return NULL; + } + + column->writable = false; + + free(column_file_name); + close(column_file_descriptor); + + return column; +} + + +int obi_close_column(OBIDMS_column_p column) +{ + //munmap? + free(column); + return 0; +} + + +void obi_column_make_unwritable(OBIDMS_column_p column) +{ + column->writable = false; +} + + +size_t obi_column_get_line_count(OBIDMS_column_p column) +{ + return (column->header)->line_count; +} + + +OBIType_t obi_column_get_data_type(OBIDMS_column_p column) +{ + return (column->header)->data_type; +} + + +OBIType_t obi_column_get_data_type_from_name(OBIDMS_p dms, const char* column_name) +{ + OBIDMS_column_header_p header; + OBIDMS_column_directory_p column_directory; + char* column_file_name; + int column_file_descriptor; + int column_dir_file_descriptor; + size_t header_size; + OBIType_t data_type; + obiversion_t version_number; + + // Get the column directory structure associated to the column + column_directory = obi_open_column_directory(dms, column_name); + if (column_directory == NULL) + { + obidebug(1, "\nProblem opening column directory"); + return -1; + } + + // Get the file descriptor associated to the column directory + column_dir_file_descriptor = dirfd(column_directory->directory); + if (column_dir_file_descriptor < 0) + { + obidebug(1, "\nProblem opening column directory"); + obi_set_errno(OBICOLDIR_UNKNOWN_ERROR); + obi_close_column_directory(column_directory); + return -1; + } + + // Calculate the header size + header_size = obi_get_platform_header_size(); + + // Get the latest version number + version_number = obi_get_latest_version_number(column_directory); + if (version_number < 0) + { + obidebug(1, "\nProblem getting the latest version number"); + obi_close_column_directory(column_directory); + close(column_dir_file_descriptor); + return -1; + } + + // Get the column file name + column_file_name = build_column_file_name(column_name, version_number); + if (column_file_name == NULL) + { + obidebug(1, "Problem building column file name"); + obi_close_column_directory(column_directory); + close(column_dir_file_descriptor); + return -1; + } + + // Open the column file (READ-ONLY) + column_file_descriptor = openat(column_dir_file_descriptor, column_file_name, O_RDONLY); + if (column_file_descriptor < 0) + { + obidebug(1, "\nCan't open column file"); + obi_set_errno(OBICOL_UNKNOWN_ERROR); + obi_close_column_directory(column_directory); + close(column_dir_file_descriptor); + free(column_file_name); + return -1; + } + + // Fill the header structure + header = mmap(NULL, + header_size, + PROT_READ, + MAP_SHARED, + column_file_descriptor, + 0 + ); + + if (header == MAP_FAILED) + { + obi_set_errno(OBICOL_UNKNOWN_ERROR); + obi_close_column_directory(column_directory); + close(column_dir_file_descriptor); + close(column_file_descriptor); + free(column_file_name); + free(header); + return -1; + } + + // Check endianness? + + data_type = header->data_type; + + free(column_file_name); + close(column_file_descriptor); + munmap(header, header_size); + return data_type; +} + + +const char* obi_column_get_elements_names(OBIDMS_column_p column) +{ + return (column->header)->elements_names; +} + + +// to be rewritten in an optimized and safe way +size_t obi_column_get_element_index_from_name(OBIDMS_column_p column, const char* element_name) +{ + char* elements_names; + char* name; + size_t element_index; + + elements_names = strdup((column->header)->elements_names); + if (elements_names == NULL) + { + obidebug(1, "\nError strdup-ing the elements names"); + return -1; + } + + element_index = 0; + + name = strtok (elements_names, ";"); // not thread safe, see strtok_r maybe + if (strcmp(element_name, name) == 0) + { + free(elements_names); + return element_index; + } + element_index++; + + while (name != NULL) + { + name = strtok (NULL, ";"); // not thread safe, see strtok_r maybe + if (strcmp(element_name, name) == 0) + { + free(elements_names); + return element_index; + } + element_index++; + } + + obidebug(1, "\nCan't find element name"); + free(elements_names); + return -1; +} + + +size_t obi_column_get_nb_elements_per_line(OBIDMS_column_p column) +{ + return (column->header)->nb_elements_per_line; +} + + + diff --git a/src/obidmscolumn.h b/src/obidmscolumn.h index 13a8b76..7503c55 100644 --- a/src/obidmscolumn.h +++ b/src/obidmscolumn.h @@ -86,6 +86,28 @@ typedef struct OBIDMS_column { } OBIDMS_column_t, *OBIDMS_column_p; +/** + * @brief Returns the latest version of a column in a column directory + * + * @param column_directory + * + * @return the latest version number kept in the version file + * @return -1 if an error occurred + */ +obiversion_t obi_get_latest_version_number(OBIDMS_column_directory_p column_directory); + + +/** + * @brief Returns the latest version of a column in a column directory + * + * @param column_name + * + * @return the latest version number kept in the version file + * @return -1 if an error occurred + */ +obiversion_t obi_column_get_latest_version_from_name(OBIDMS_p dms, const char* column_name); + + /** * @brief Returns the header size in bytes of a column on this platform. * @@ -103,7 +125,7 @@ size_t obi_get_platform_header_size(); /** * @brief Creates a column. * - * @param dms a pointer on an OBIDMS column + * @param dms a pointer on an OBIDMS * @param column_name the name of the new column * @param type the OBIType code used to create the column * @param nb_elements the number of elements to be stored @@ -120,15 +142,123 @@ OBIDMS_column_p obi_create_column(OBIDMS_p dms, /** - * @brief Returns the latest column version in the `dms` database + * @brief Opens a column in read-only mode. * - * @param dms a pointer as returned by obi_create_dms() or obi_open_dms() + * @param dms a pointer on an OBIDMS * @param column_name the name of the column + * @param version_number the version of the column that should be opened * - * @return the bigger version number used for this column - * @return -1 if the column does not exist + * @return a pointer to the opened column + * + * @since July 2015 + * @author Celine Mercier (celine.mercier@metabarcoding.org) */ -obiversion_t obi_get_latest_version_number(OBIDMS_column_directory_p column_directory); +OBIDMS_column_p obi_open_column(OBIDMS_p dms, const char* column_name, obiversion_t version_number); + + +/** + * @brief Closes a column. + * + * @param column a pointer on an OBIDMS column + * + * @return 0 if the operation was successfully completed + * @return -1 if an error occurred + * + * @since July 2015 + * @author Celine Mercier (celine.mercier@metabarcoding.org) + */ +int obi_close_column(OBIDMS_column_p column); + + +/** + * @brief Sets the 'writable' header attribute of an OBIDMS column to False. + * + * @param column a pointer on an OBIDMS column + * + * @since July 2015 + * @author Celine Mercier (celine.mercier@metabarcoding.org) + */ +void obi_column_make_unwritable(OBIDMS_column_p column); + + +/** + * @brief Recovers the line count of an OBIDMS column. + * + * @param column a pointer on an OBIDMS column + * + * @return the line count of the column + * + * @since July 2015 + * @author Celine Mercier (celine.mercier@metabarcoding.org) + */ +size_t obi_column_get_line_count(OBIDMS_column_p column); + + +/** + * @brief Recovers the data type of an OBIDMS column. + * + * @param column a pointer on an OBIDMS column + * + * @return the data type of the column + * + * @since July 2015 + * @author Celine Mercier (celine.mercier@metabarcoding.org) + */ +OBIType_t obi_column_get_data_type(OBIDMS_column_p column); + + +/** + * @brief Recovers the data type of an OBIDMS column from the column name. + * + * @param dms a pointer on an OBIDMS + * @param column_name the name of an OBIDMS column + * + * @return the data type of the column + * + * @since July 2015 + * @author Celine Mercier (celine.mercier@metabarcoding.org) + */ +OBIType_t obi_column_get_data_type_from_name(OBIDMS_p dms, const char* column_name); + + +/** + * @brief Recovers the elements names of an OBIDMS column. + * + * @param column a pointer on an OBIDMS column + * + * @return the elements names + * + * @since July 2015 + * @author Celine Mercier (celine.mercier@metabarcoding.org) + */ +const char* obi_column_get_elements_names(OBIDMS_column_p column); + + +/** + * @brief Recovers the index of an element in an OBIDMS column from its name. + * + * @param column a pointer on an OBIDMS column + * @param element_name the name of the element + * + * @return the index of the element in a line of the column + * + * @since July 2015 + * @author Celine Mercier (celine.mercier@metabarcoding.org) + */ +size_t obi_column_get_element_index_from_name(OBIDMS_column_p column, const char* element_name); + + +/** + * @brief Recovers the number of elements per line in an OBIDMS column. + * + * @param column a pointer on an OBIDMS column + * + * @return the number of elements per line + * + * @since July 2015 + * @author Celine Mercier (celine.mercier@metabarcoding.org) + */ +size_t obi_column_get_nb_elements_per_line(OBIDMS_column_p column); #endif /* OBIDMSCOLUMN_H_ */ diff --git a/src/obidmscolumn_int.c b/src/obidmscolumn_int.c new file mode 100644 index 0000000..25ef3c1 --- /dev/null +++ b/src/obidmscolumn_int.c @@ -0,0 +1,49 @@ +/**************************************************************************** + * OBIDMS_column_int functions * + ****************************************************************************/ + +/** + * @file obidsmcolumn_int.c + * @author Celine Mercier + * @date July 21st 2015 + * @brief Functions handling OBIColumns containing data with the OBIType OBI_INT. + */ + + +#include +#include + +#include "obidmscolumn.h" +#include "obitypes.h" +#include "obierrno.h" +#include "obidebug.h" + + +/********************************************************************** + * + * D E F I N I T I O N O F T H E P U B L I C F U N C T I O N S + * + **********************************************************************/ + +int obi_column_set_int(OBIDMS_column_p column, size_t line_nb, size_t element_idx, obiint_t value) +{ + // check if can write? + size_t nb_elements_per_line = -1; + nb_elements_per_line = (column->header)->nb_elements_per_line; + *(((obiint_t*) (column->data)) + (line_nb * nb_elements_per_line) + element_idx) = value; + return 0; +} + + +obiint_t obi_column_get_int(OBIDMS_column_p column, size_t line_nb, size_t element_idx) +{ + size_t nb_elements_per_line = -1; + nb_elements_per_line = (column->header)->nb_elements_per_line; + return *(((obiint_t*) (column->data)) + (line_nb * nb_elements_per_line) + element_idx); +} + + +//obiint_t* obi_column_get_line_address_int(OBIDMS_column_p column, size_t nb_elements_per_line, size_t line_nb) +//{ +// return (((obiint_t*) (column->data)) + (line_nb * nb_elements_per_line)); +//} diff --git a/src/obidmscolumn_int.h b/src/obidmscolumn_int.h new file mode 100644 index 0000000..c35d02d --- /dev/null +++ b/src/obidmscolumn_int.h @@ -0,0 +1,59 @@ +/**************************************************************************** + * OBIDMS_column_int header file * + ****************************************************************************/ + +/** + * @file obidsmcolumn_int.h + * @author Celine Mercier + * @date July 21st 2015 + * @brief Header file for the functions handling OBIColumns containing data with the OBIType OBI_INT. + */ + + +#include +#include + +#include "obidmscolumn.h" +#include "obitypes.h" + + +/** + * @brief Sets a value in an OBIDMS column containing data with the type OBI_INT. + * + * @param column a pointer as returned by obi_create_column() + * @warning Pointers returned by obi_open_column() don't allow writing. + * + * @param line_nb the number of the line where the value should be set + * + * @param element_idx the index of the element that should be set in the line + * + * @param value the value that should be set + * + * @return an integer value indicating the success of the operation. + * + * @retvalue 0 on success + * @retvalue -1 on failure and the `obi_errno` variable is set. + * + * @since July 2015 + * @author Celine Mercier (celine.mercier@metabarcoding.org) + */ +int obi_column_set_int(OBIDMS_column_p column, size_t line_nb, size_t element_idx, obiint_t value); + + +/** + * @brief Recovers a value in an OBIDMS column containing data with the type OBI_INT. + * + * @param column a pointer as returned by obi_create_column() + * + * @param line_nb the number of the line where the value should be recovered + * + * @param element_idx the index of the element that should be recovered in the line + * + * @return the recovered value + * + * @since July 2015 + * @author Celine Mercier (celine.mercier@metabarcoding.org) + */ +obiint_t obi_column_get_int(OBIDMS_column_p column, size_t line_nb, size_t element_idx); + +