/**************************************************************************** * OBIDMS_column functions * ****************************************************************************/ /** * @file OBIDMS_column.h * @author Celine Mercier * @date 22 May 2015 * @brief Functions for the shared elements of all the OBIColumn structures. */ #include #include #include #include /* mmap() is defined in this header */ /************************************************************************* * * D E C L A R A 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 * *************************************************************************/ /** * @brief Internal function building the file name for a column. * * The function builds the file name corresponding to a column of an OBIDMS. * * @warning The returned pointer has to be freed by the caller. * * @param name the name of the column of the OBIDMS * * @return a pointer to the filename name * @retvalue NULL if an error occurs * * ###Error values * - OBIDMS_MEMORY_ERROR : something wrong occured during memory allocation. * * @since May 2015 * @author Eric Coissac (eric.coissac@metabarcoding.org) */ static char *build_column_name(const char *name, obiversion_t version); /** * @brief Internal function building the file name for a version column file. * * The version column file indicate the latest version number for a column. * This function returns the name of the file storing this information * * @warning The returned pointer has to be freed by the caller. * * @param name the name of the column of the OBIDMS * * @return a pointer to the filename name * @retvalue NULL if an error occurs * * ###Error values * - OBIDMS_MEMORY_ERROR : something wrong occurs during memory allocation. * * @since May 2015 * @author Eric Coissac (eric.coissac@metabarcoding.org) */ static char *build_version_name(const char *name); /** * @brief Internal function returning a new column version number * in the `dms` database * * @param dms a pointer as returned by obi_create_dms() or obi_open_dms() * @param name the name of the column * @param block is the call is blocking or not * - `true` the call is blocking * - `false` the call is not blocking * * @return the bigger version number used for this column * @retvalue -1 if the column does not exist * * @since May 2015 * @author Eric Coissac (eric.coissac@metabarcoding.org) */ static obiversion_t obi_new_version(OBIDMS_p dms,char *name, bool block); /** * @brief Internal function creating a new column version file * in the `dms` database * * The new file is initialized with the minimum version number `0`. * * @param dms a pointer as returned by obi_create_dms() or obi_open_dms() * @param name the name of the column * * @return the next usable version number for this comumn : `0` * @retvalue -1 if the column does not exist * * @since May 2015 * @author Eric Coissac (eric.coissac@metabarcoding.org) */ static int create_version(OBIDMS_p dms,char *name); /************************************************************************ * * 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 * ************************************************************************/ static char *build_column_name(const char *name,obiversion_t version) { char *filename; // Build the database directory name if (asprintf(&filename,"%s@%d.odc",name,version) < 0) { obi_set_errno(OBIDMS_MEMORY_ERROR); return NULL; } return filename; } static char *build_version_name(const char *name) { char *filename; // Build the database directory name if (asprintf(&filename,"%s.odv",name) < 0) { obi_set_errno(OBIDMS_MEMORY_ERROR); return NULL; } return filename; } static obiversion_t obi_new_version(OBIDMS_p dms,char *name, bool block) { off_t locsize=sizeof(bool) + sizeof(obiversion_t); obiversion_t newversion=0; char * versionfile; int directoryfd; int versionfd; bool little; int lockmode; // Select the correct lockf operation according to the blocking mode if (block) lockmode=F_LOCK; else lockmode=F_TLOCK; // build the version file name versionfile = build_version_name(name); if (versionfile==NULL) return -1; // Get the file descriptior associated to the database directory directoryfd = dirfd(dms->directory); if (directoryfd < 0) { obi_set_errno(OBIDMS_UNKNOWN_ERROR); free(versionfile); return -1; } //open the version file //versionfd = openat(directoryfd, versionfile, O_RDWR); versionfd = open(versionfile, O_RDWR); if (versionfd < 0) { free(versionfile); if (errno == ENOENT) { return create_version(dms, name); } else { obi_set_errno(OBIDMS_UNKNOWN_ERROR); return -1; } } // Test if the version file size is ok if (lseek(versionfd, SEEK_END, 0) < locsize) { close(versionfd); obi_set_errno(OBIDMS_UNKNOWN_ERROR); free(versionfile); return -1; } // prepare the file for locking if (lseek(versionfd, SEEK_SET, 0) != 0) { close(versionfd); obi_set_errno(OBIDMS_UNKNOWN_ERROR); free(versionfile); return -1; } // Lock the file if (lockf(versionfd, lockmode, locsize) < -1) { close(versionfd); obi_set_errno(OBIDMS_UNKNOWN_ERROR); free(versionfile); return -1; } // read the endianess of the file if (read(versionfd, &little, sizeof(bool)) < sizeof(bool)) { close(versionfd); obi_set_errno(OBIDMS_UNKNOWN_ERROR); free(versionfile); return -1; } // check if endianess is correct if (little != obi_is_little_endian()) { close(versionfd); obi_set_errno(OBIDMS_BAD_ENDIAN_ERROR); free(versionfile); return -1; } // read the current version number if (read(versionfd, &newversion, sizeof(obiversion_t)) < sizeof(obiversion_t)) { close(versionfd); obi_set_errno(OBIDMS_UNKNOWN_ERROR); free(versionfile); return -1; } newversion++; // write the new version number if (lseek(versionfd,SEEK_SET,sizeof(bool)) != sizeof(bool)) { close(versionfd); obi_set_errno(OBIDMS_UNKNOWN_ERROR); free(versionfile); return -1; } if (write(versionfd, &newversion, sizeof(obiversion_t)) < sizeof(obiversion_t)) { close(versionfd); obi_set_errno(OBIDMS_UNKNOWN_ERROR); free(versionfile); return -1; } // prepare for the unlocking if (lseek(versionfd,SEEK_SET,0) != 0) { close(versionfd); obi_set_errno(OBIDMS_UNKNOWN_ERROR); free(versionfile); return -1; } // unlock the file if (lockf(versionfd, F_ULOCK, locsize) < -1) { close(versionfd); obi_set_errno(OBIDMS_UNKNOWN_ERROR); free(versionfile); return -1; } close(versionfd); free(versionfile); return newversion; } static int create_version(OBIDMS_p dms,char *name) { off_t locsize=sizeof(bool) + sizeof(obiversion_t); obiversion_t version=0; char * versionfile; int directoryfd; int versionfd; bool little; versionfile = build_version_name(name); if (versionfile==NULL) return -1; directoryfd = dirfd(dms->directory); if (directoryfd < 0) { obi_set_errno(OBIDMS_UNKNOWN_ERROR); free(versionfile); return -1; } //versionfd = openat(directoryfd, // versionfile, // O_RDWR|O_CREAT|O_EXCL, // 666); versionfd = open(versionfile, O_RDWR|O_CREAT|O_EXCL, 666); if (versionfd < 0) { obi_set_errno(OBIDMS_UNKNOWN_ERROR); free(versionfile); return -1; } // Lock the file if (lockf(versionfd, F_LOCK, locsize) < -1) { close(versionfd); obi_set_errno(OBIDMS_UNKNOWN_ERROR); free(versionfile); return -1; } if (ftruncate(versionfd,locsize) < 0) { close(versionfd); obi_set_errno(OBIDMS_UNKNOWN_ERROR); free(versionfile); return -1; } if (lseek(versionfd,SEEK_SET,0) != 0) { close(versionfd); obi_set_errno(OBIDMS_UNKNOWN_ERROR); free(versionfile); return -1; } little = obi_is_little_endian(); if (write(versionfd, &little, sizeof(bool)) < sizeof(bool)) { close(versionfd); obi_set_errno(OBIDMS_UNKNOWN_ERROR); free(versionfile); return -1; } if (write(versionfd, &version, sizeof(obiversion_t)) < sizeof(obiversion_t)) { close(versionfd); obi_set_errno(OBIDMS_UNKNOWN_ERROR); free(versionfile); return -1; } // prepare for the unlocking if (lseek(versionfd,SEEK_SET,0) != 0) { close(versionfd); obi_set_errno(OBIDMS_UNKNOWN_ERROR); free(versionfile); return -1; } // unlock the file if (lockf(versionfd, F_ULOCK, locsize) < -1) { close(versionfd); obi_set_errno(OBIDMS_UNKNOWN_ERROR); free(versionfile); return -1; } close(versionfd); free(versionfile); return version; } /*********************************************************************** * * 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 * ***********************************************************************/ obiversion_t obi_latest_version(OBIDMS_p dms,char *name) { off_t locsize=sizeof(bool) + sizeof(obiversion_t); obiversion_t version=0; char * versionfile; int directoryfd; int versionfd; bool little; versionfile = build_version_name(name); if (versionfile==NULL) return -1; directoryfd = dirfd(dms->directory); if (directoryfd < 0) { obi_set_errno(OBIDMS_UNKNOWN_ERROR); free(versionfile); return -1; } //versionfd = openat(directoryfd,versionfile,O_RDWR); versionfd = open(versionfile,O_RDWR); if (versionfd < 0) { obi_set_errno(OBIDMS_UNKNOWN_ERROR); free(versionfile); return -1; } if (lseek(versionfd,SEEK_END,0) < locsize) { close(versionfd); obi_set_errno(OBIDMS_UNKNOWN_ERROR); free(versionfile); return -1; } if (lseek(versionfd,SEEK_SET,0) != 0) { close(versionfd); obi_set_errno(OBIDMS_UNKNOWN_ERROR); free(versionfile); return -1; } if (read(versionfd, &little, sizeof(bool)) < sizeof(bool)) { close(versionfd); obi_set_errno(OBIDMS_UNKNOWN_ERROR); free(versionfile); return -1; } if (little != obi_is_little_endian()) { close(versionfd); obi_set_errno(OBIDMS_BAD_ENDIAN_ERROR); free(versionfile); return -1; } if (read(versionfd, &version, sizeof(obiversion_t)) < sizeof(obiversion_t)) { close(versionfd); obi_set_errno(OBIDMS_UNKNOWN_ERROR); free(versionfile); return -1; } close(versionfd); free(versionfile); return version; } size_t obi_get_platform_header_size() { return getpagesize() * 1; } OBIDMS_column_p obi_create_column(OBIDMS_p dms, char *name, OBIType_t type, size_t nbelements) { OBIDMS_column_p newcolumn=NULL; OBIDMS_column_header_p header; size_t filesize; obiversion_t version; char * columnfile; int columnfd; int directoryfd; size_t hsize; size_t dsize; directoryfd = dirfd(dms->directory); if (directoryfd < 0) { obi_set_errno(OBIDMS_UNKNOWN_ERROR); return NULL; } hsize = obi_get_platform_header_size(); dsize = obi_array_sizeof(type,nbelements); filesize = hsize + dsize; version = obi_new_version(dms,name,true); if (version < 0) { obi_set_errno(OBIDMS_UNKNOWN_ERROR); return NULL; } columnfile = build_column_name(name,version); //columnfd = openat(directoryfd, // columnfile, // O_RDWR|O_CREAT|O_EXCL, // 666); columnfd = open(columnfile, O_RDWR|O_CREAT|O_EXCL, 666); if (ftruncate(columnfd,filesize) < 0) { close(columnfd); obi_set_errno(OBIDMS_UNKNOWN_ERROR); free(columnfile); return NULL; } newcolumn = (OBIDMS_column_p) malloc(sizeof(OBIDMS_column_t)); if (newcolumn) { close(columnfd); obi_set_errno(OBIDMS_MEMORY_ERROR); free(columnfile); return NULL; } newcolumn->dms = dms; newcolumn->header = mmap(NULL, hsize, PROT_READ | PROT_WRITE, MAP_SHARED, columnfd, 0 ); if (newcolumn->header == MAP_FAILED) { close(columnfd); obi_set_errno(OBIDMS_MEMORY_ERROR); free(columnfile); free(newcolumn); return NULL; } newcolumn->data = mmap(NULL, dsize, PROT_READ | PROT_WRITE, MAP_SHARED, columnfd, hsize ); if (newcolumn->data == MAP_FAILED) { munmap(newcolumn->header,hsize); close(columnfd); obi_set_errno(OBIDMS_MEMORY_ERROR); free(columnfile); free(newcolumn); return NULL; } newcolumn->writable= true; header = newcolumn->header; header->little_endian = obi_is_little_endian(); header->header_size = hsize; header->line_count = nbelements; header->line_used = 0; header->data_type = type; header->creation_date = time(NULL); header->version = version; header->comments[0] = 0x0; strncpy(header->name,name,OBIDMS_MAX_COLNAME); free(columnfile); return newcolumn; } // if( access( fname, F_OK ) != -1 ) { // // file exists // } else { // // file doesn't exist // }