2015-09-30 12:03:46 +02:00
/********************************************************************
* OBIDMS functions *
********************************************************************/
/**
* @file obidms.c
* @author Eric Coissac (eric.coissac@metabarcoding.org)
* @date 23 May 2015
* @brief OBIDMS functions.
2015-05-23 16:29:06 +03:00
*/
2015-09-30 12:03:46 +02:00
2015-06-17 16:51:16 +02:00
#include <stdlib.h>
#include <stdio.h>
2015-06-23 18:35:34 +02:00
#include <string.h>
2015-11-18 15:35:09 +01:00
#include <stdbool.h>
2015-06-23 18:35:34 +02:00
#include <sys/stat.h>
2015-11-03 14:22:00 +01:00
#include <fcntl.h>
2015-06-23 18:35:34 +02:00
#include <sys/types.h>
#include <dirent.h>
2016-04-29 17:46:36 +02:00
#include <unistd.h>
2017-08-03 16:33:12 +02:00
#include <libgen.h> /* <EC> : Added July 28th 2017 to include basename */
2018-10-07 18:53:25 +02:00
#include <sys/mman.h>
2019-03-13 11:17:25 +01:00
#include <math.h>
2015-06-17 16:51:16 +02:00
#include "obidms.h"
2015-06-23 18:35:34 +02:00
#include "obierrno.h"
2015-07-31 18:03:48 +02:00
#include "obidebug.h"
#include "obidmscolumn.h"
2017-08-03 16:33:12 +02:00
#include "obiview.h"
2016-04-15 10:49:12 +02:00
#include "obiblob_indexer.h"
2016-04-08 15:38:57 +02:00
#include "utils.h"
2015-11-16 14:37:51 +01:00
#include "obilittlebigman.h"
2018-10-07 18:53:25 +02:00
#include "libjson/json_utils.h"
2019-09-21 16:47:22 +02:00
#include "obisig.h"
2015-07-31 18:03:48 +02:00
2015-08-03 15:10:39 +02:00
2015-09-30 12:03:46 +02:00
#define DEBUG_LEVEL 0 // TODO has to be defined somewhere else (cython compil flag?)
2015-05-23 16:29:06 +03:00
2015-05-26 21:36:55 +02:00
2017-11-24 17:58:47 +01:00
// Initialize global list of opened DMS and their associated counters
2017-10-16 10:35:07 +02:00
OBIDMS_p global_opened_dms_list [ MAX_NB_OPENED_DMS + 1 ] = { 0 };
2017-11-24 17:58:47 +01:00
int global_opened_dms_counter_list [ MAX_NB_OPENED_DMS + 1 ] = { 0 };
2017-10-16 10:35:07 +02:00
2015-06-23 18:35:34 +02:00
/**************************************************************************
2015-05-26 21:36:55 +02:00
*
2015-06-23 18:35:34 +02:00
* 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
2015-05-26 21:36:55 +02:00
*
2015-06-23 18:35:34 +02:00
**************************************************************************/
2015-05-26 21:36:55 +02:00
2015-05-23 16:29:06 +03:00
/**
2015-09-30 12:03:46 +02:00
* Internal function building the OBIDMS directory name from an OBIDMS name.
2015-05-23 16:29:06 +03:00
*
2015-06-10 15:19:02 +02:00
* The function builds the directory name corresponding to an OBIDMS.
2015-09-30 12:03:46 +02:00
* It also checks that the name is not too long.
2015-05-23 16:29:06 +03:00
*
* @warning The returned pointer has to be freed by the caller.
*
2015-09-30 12:03:46 +02:00
* @param dms_name The name of the OBIDMS.
2015-05-23 16:29:06 +03:00
*
2015-09-30 12:03:46 +02:00
* @returns A pointer to the directory name.
* @retval NULL if an error occurred.
2015-05-23 16:29:06 +03:00
*
* @since May 2015
* @author Eric Coissac (eric.coissac@metabarcoding.org)
*/
2015-09-30 12:03:46 +02:00
static char * build_directory_name ( const char * dms_name );
2015-05-23 16:29:06 +03:00
2015-06-10 15:19:02 +02:00
2015-11-16 14:37:51 +01:00
/**
* Internal function building the informations file name from an OBIDMS name.
*
* The function builds the file name for the informations file of an OBIDMS.
*
* @warning The returned pointer has to be freed by the caller.
*
* @param dms_name The name of the OBIDMS.
*
2018-10-07 18:53:25 +02:00
* @returns A pointer on the file name.
2015-11-16 14:37:51 +01:00
* @retval NULL if an error occurred.
*
* @since November 2015
* @author Celine Mercier (celine.mercier@metabarcoding.org)
*/
static char * build_infos_file_name ( const char * dms_name );
2018-10-07 18:53:25 +02:00
/**
* Internal function calculating the initial size of the file where the informations about a DMS are stored.
*
* @returns The initial size of the file in bytes, rounded to a multiple of page size.
*
* @since September 2018
* @author Celine Mercier (celine.mercier@metabarcoding.org)
*/
2018-10-17 12:00:40 +02:00
static size_t get_platform_infos_file_size ( void );
2018-10-07 18:53:25 +02:00
/**
* @brief Internal function enlarging a DMS information file.
*
* @param dms A pointer on the DMS.
* @param new_size The new size needed, in bytes (not necessarily rounded to a page size multiple).
*
* @retval 0 if the operation was successfully completed.
* @retval -1 if an error occurred.
*
* @since September 2018
* @author Celine Mercier (celine.mercier@metabarcoding.org)
*/
static int enlarge_infos_file ( OBIDMS_p dms , size_t new_size );
/**
* @brief Internal function mapping a DMS information file and returning the mapped structure stored in it.
*
* The function checks that endianness of the platform and of the DMS match.
*
* @param dms_file_descriptor The file descriptor of the DMS directory.
* @param dms_name The base name of the DMS.
*
* @returns A pointer on the mapped DMS infos structure.
* @retval NULL if an error occurred.
*
* @since September 2018
* @author Celine Mercier (celine.mercier@metabarcoding.org)
*/
static OBIDMS_infos_p map_infos_file ( int dms_file_descriptor , const char * dms_name );
/**
* @brief Unmaps a DMS information file.
*
* @param dms A pointer on the OBIDMS.
*
* @returns A value indicating the success of the operation.
* @retval 0 if the operation was successfully completed.
* @retval -1 if an error occurred.
*
* @since October 2018
* @author Celine Mercier (celine.mercier@metabarcoding.org)
*/
static int unmap_infos_file ( OBIDMS_p dms );
2015-11-16 14:37:51 +01:00
/**
* Internal function creating the file containing basic informations on the OBIDMS.
*
2018-10-07 18:53:25 +02:00
* This file contains an OBIDMS_infos structure.
2015-11-16 14:37:51 +01:00
*
* @warning The returned pointer has to be freed by the caller.
*
2018-10-07 18:53:25 +02:00
* @param dms_file_descriptor The file descriptor of the DMS directory.
* @param dms_name The base name of the DMS.
2015-11-16 14:37:51 +01:00
*
* @retval 0 if the operation was successfully completed.
* @retval -1 if an error occurred.
*
* @since November 2015
* @author Celine Mercier (celine.mercier@metabarcoding.org)
*/
2018-10-07 18:53:25 +02:00
static int create_dms_infos_file ( int dms_file_descriptor , const char * dms_name );
2015-11-16 14:37:51 +01:00
2017-10-16 10:35:07 +02:00
/**
* Internal function adding a DMS in the global list of DMS opened by a program.
*
* @param dms A pointer on the DMS to add.
*
* @retval 0 if the operation was successfully completed.
* @retval -1 if an error occurred.
*
* @since October 2017
* @author Celine Mercier (celine.mercier@metabarcoding.org)
*/
static int list_dms ( OBIDMS_p dms );
/**
* Internal function removing a DMS from the global list of DMS opened by a program.
*
* @param dms A pointer on the DMS to remove.
2017-11-24 17:58:47 +01:00
* @param force Whether the DMS should be unlisted even if it is opened more than once.
*
* @retval 0 if the operation was successfully completed.
* @retval -1 if the DMS was not found.
2017-10-16 10:35:07 +02:00
*
* @since October 2017
* @author Celine Mercier (celine.mercier@metabarcoding.org)
*/
2017-11-24 17:58:47 +01:00
static int unlist_dms ( OBIDMS_p dms , bool force );
/**
* Internal function checking if a DMS is already in the global list of DMS opened by the program.
*
* @param full_dms_path The absolute path to the DMS directory.
*
* @returns A pointer on the DMS if it is already opened, or NULL if it was not opened.
*
* @since November 2017
* @author Celine Mercier (celine.mercier@metabarcoding.org)
*/
static OBIDMS_p check_if_dms_in_list ( const char * full_dms_path );
/**
* Internal function returning the count for an opened DMS (how many times the DMS is opened) in the global list of DMS opened by the program.
*
* @param dms A pointer on the DMS.
*
* @returns The count indicating how many times the DMS has been opened by the program.
*
* @retval -1 if the DMS was not found.
*
* @since November 2017
* @author Celine Mercier (celine.mercier@metabarcoding.org)
*/
static int dms_count_in_list ( OBIDMS_p dms );
2017-10-16 10:35:07 +02:00
2015-06-23 18:35:34 +02:00
/************************************************************************
2015-05-26 21:36:55 +02:00
*
2015-06-23 18:35:34 +02:00
* 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
2015-05-26 21:36:55 +02:00
*
2015-06-23 18:35:34 +02:00
************************************************************************/
2015-05-26 21:36:55 +02:00
2015-09-30 12:03:46 +02:00
static char * build_directory_name ( const char * dms_name )
2015-06-17 16:51:16 +02:00
{
2015-09-30 12:03:46 +02:00
char * directory_name ;
2015-06-17 16:51:16 +02:00
// Build the database directory name
2016-03-21 11:33:06 +01:00
directory_name = ( char * ) malloc (( strlen ( dms_name ) + 8 ) * sizeof ( char ));
if ( sprintf ( directory_name , "%s.obidms" , dms_name ) < 0 )
2015-06-17 16:51:16 +02:00
{
obi_set_errno ( OBIDMS_MEMORY_ERROR );
2015-08-03 15:10:39 +02:00
obidebug ( 1 , " \n Problem building an OBIDMS directory name" );
2015-06-17 16:51:16 +02:00
return NULL ;
}
// Test if the database name is not too long
if ( strlen ( directory_name ) >= OBIDMS_MAX_NAME )
{
obi_set_errno ( OBIDMS_LONG_NAME_ERROR );
2015-08-03 15:10:39 +02:00
obidebug ( 1 , " \n Problem building an OBIDMS directory name" );
2015-06-17 16:51:16 +02:00
free ( directory_name );
return NULL ;
}
return directory_name ;
}
2015-11-16 14:37:51 +01:00
static char * build_infos_file_name ( const char * dms_name )
{
char * file_name ;
// Build file name
2016-03-21 11:33:06 +01:00
file_name = ( char * ) malloc (( strlen ( dms_name ) + 7 ) * sizeof ( char ));
if ( sprintf ( file_name , "%s_infos" , dms_name ) < 0 )
2015-11-16 14:37:51 +01:00
{
obi_set_errno ( OBIDMS_MEMORY_ERROR );
obidebug ( 1 , " \n Problem building an informations file name" );
return NULL ;
}
return file_name ;
}
2018-10-07 18:53:25 +02:00
static size_t get_platform_infos_file_size ()
2015-11-16 14:37:51 +01:00
{
2018-10-07 18:53:25 +02:00
size_t infos_size ;
size_t rounded_infos_size ;
double multiple ;
2015-11-16 14:37:51 +01:00
2018-10-07 18:53:25 +02:00
infos_size = sizeof ( OBIDMS_infos_t );
multiple = ceil (( double ) ( infos_size ) / ( double ) getpagesize ());
rounded_infos_size = multiple * getpagesize ();
return rounded_infos_size ;
}
static int enlarge_infos_file ( OBIDMS_p dms , size_t new_size )
{
int infos_file_descriptor ;
double multiple ;
size_t rounded_new_size ;
char * file_name ;
2015-11-16 14:37:51 +01:00
// Create file name
2018-10-07 18:53:25 +02:00
file_name = build_infos_file_name ( dms -> dms_name );
if ( file_name == NULL )
return - 1 ;
// Open infos file
infos_file_descriptor = openat ( dms -> dir_fd , file_name , O_RDWR , 0777 );
if ( infos_file_descriptor < 0 )
{
obi_set_errno ( OBIDMS_UNKNOWN_ERROR );
obidebug ( 1 , " \n Error opening a DMS information file" );
free ( file_name );
return - 1 ;
}
free ( file_name );
// Round new size to a multiple of page size // TODO make function in utils
multiple = ceil (( double ) new_size / ( double ) getpagesize ());
rounded_new_size = multiple * getpagesize ();
2021-03-11 15:12:40 +13:00
// Unmap the entire file before truncating it (WSL requirement)
if ( munmap ( dms -> infos , ( dms -> infos ) -> file_size ) < 0 )
{
obi_set_errno ( OBIDMS_UNKNOWN_ERROR );
obidebug ( 1 , " \n Error munmapping a DMS information file when enlarging" );
close ( infos_file_descriptor );
return - 1 ;
}
2018-10-07 18:53:25 +02:00
// Enlarge the file
if ( ftruncate ( infos_file_descriptor , rounded_new_size ) < 0 )
{
obi_set_errno ( OBIDMS_UNKNOWN_ERROR );
obidebug ( 1 , " \n Error enlarging a DMS information file" );
close ( infos_file_descriptor );
return - 1 ;
}
2021-03-11 15:12:40 +13:00
// Remap the file
2018-10-07 18:53:25 +02:00
dms -> infos = mmap ( NULL ,
rounded_new_size ,
PROT_READ | PROT_WRITE ,
MAP_SHARED ,
infos_file_descriptor ,
0
);
if ( dms -> infos == MAP_FAILED )
{
obi_set_errno ( OBIDMS_UNKNOWN_ERROR );
obidebug ( 1 , " \n Error re-mmapping a DMS information file after enlarging the file" );
close ( infos_file_descriptor );
return - 1 ;
}
// Set new size
( dms -> infos ) -> file_size = rounded_new_size ;
if ( close ( infos_file_descriptor ) < 0 )
{
obi_set_errno ( OBIDMS_UNKNOWN_ERROR );
obidebug ( 1 , " \n Error closing a DMS information file" );
return - 1 ;
}
return 0 ;
}
static OBIDMS_infos_p map_infos_file ( int dms_file_descriptor , const char * dms_name )
{
char * file_name ;
OBIDMS_infos_p dms_infos ;
int file_descriptor ;
size_t min_size ;
size_t full_size ;
bool little_endian_platform ;
// Build file name
file_name = build_infos_file_name ( dms_name );
if ( file_name == NULL )
return NULL ;
// Open file
file_descriptor = openat ( dms_file_descriptor ,
file_name ,
O_RDWR , 0777 );
if ( file_descriptor < 0 )
{
obi_set_errno ( OBIDMS_UNKNOWN_ERROR );
obidebug ( 1 , " \n Error opening a DMS information file (DMS %s)" , dms_name );
free ( file_name );
return NULL ;
}
free ( file_name );
// Map minimum size to read endianness and file size
// (fread() fails to read properly from the structure in the file because of padding)
min_size = get_platform_infos_file_size ();
dms_infos = mmap ( NULL ,
min_size ,
PROT_READ | PROT_WRITE ,
MAP_SHARED ,
file_descriptor ,
0
);
if ( dms_infos == NULL )
{
obi_set_errno ( OBIDMS_UNKNOWN_ERROR );
obidebug ( 1 , " \n Error mapping a DMS information file" );
return NULL ;
}
// Check endianness of the platform and DMS
little_endian_platform = obi_is_little_endian ();
if ( little_endian_platform != dms_infos -> little_endian )
{
obi_set_errno ( OBIDMS_BAD_ENDIAN_ERROR );
obidebug ( 1 , " \n Error: The DMS and the platform have different endianness" );
close ( file_descriptor );
return NULL ;
}
// Read actual file size
full_size = dms_infos -> file_size ;
// Unmap the minimum size and remap the file with the full size
if ( munmap ( dms_infos , min_size ) < 0 )
{
obi_set_errno ( OBIDMS_UNKNOWN_ERROR );
obidebug ( 1 , " \n Error munmapping a DMS information file" );
close ( file_descriptor );
return NULL ;
}
dms_infos = mmap ( NULL ,
full_size ,
PROT_READ | PROT_WRITE ,
MAP_SHARED ,
file_descriptor ,
0
);
if ( dms_infos == NULL )
{
obi_set_errno ( OBIDMS_UNKNOWN_ERROR );
obidebug ( 1 , " \n Error mapping a DMS information file" );
return NULL ;
}
if ( close ( file_descriptor ) < 0 )
{
obi_set_errno ( OBIDMS_UNKNOWN_ERROR );
obidebug ( 1 , " \n Error closing a DMS information file" );
return NULL ;
}
return dms_infos ;
}
static int unmap_infos_file ( OBIDMS_p dms )
{
OBIDMS_infos_p dms_infos ;
char * file_name ;
int file_descriptor ;
size_t file_size ;
dms_infos = dms -> infos ;
// Build file name
file_name = build_infos_file_name ( dms -> dms_name );
if ( file_name == NULL )
return - 1 ;
// Open file
file_descriptor = openat ( dms -> dir_fd ,
file_name ,
O_RDWR , 0777 );
if ( file_descriptor < 0 )
{
obi_set_errno ( OBIDMS_UNKNOWN_ERROR );
obidebug ( 1 , " \n Error opening a DMS information file (DMS %s) to unmap it" , dms -> dms_name );
free ( file_name );
return - 1 ;
}
free ( file_name );
// Unmap the DMS infos structure
file_size = dms_infos -> file_size ;
if ( munmap ( dms_infos , file_size ) < 0 )
{
obi_set_errno ( OBIDMS_UNKNOWN_ERROR );
obidebug ( 1 , " \n Error unmapping a DMS information file" );
close ( file_descriptor );
return - 1 ;
}
if ( close ( file_descriptor ) < 0 )
{
obi_set_errno ( OBIDMS_UNKNOWN_ERROR );
obidebug ( 1 , " \n Error closing a DMS information file" );
return - 1 ;
}
return 0 ;
}
static int create_dms_infos_file ( int dms_file_descriptor , const char * dms_name )
{
char * file_name ;
int infos_file_descriptor ;
size_t file_size ;
// Build file name
2015-11-16 14:37:51 +01:00
file_name = build_infos_file_name ( dms_name );
if ( file_name == NULL )
return - 1 ;
// Create file
2017-07-28 15:56:21 +02:00
infos_file_descriptor = openat ( dms_file_descriptor ,
file_name ,
2018-10-07 18:53:25 +02:00
O_RDWR | O_CREAT | O_EXCL ,
0777 );
2015-11-16 14:37:51 +01:00
if ( infos_file_descriptor < 0 )
{
obi_set_errno ( OBIDMS_UNKNOWN_ERROR );
2018-10-07 18:53:25 +02:00
obidebug ( 1 , " \n Error creating a DMS information file (DMS %s)" , dms_name );
2015-11-16 14:37:51 +01:00
free ( file_name );
return - 1 ;
}
free ( file_name );
2018-10-07 18:53:25 +02:00
// Truncate file to the initial size
file_size = get_platform_infos_file_size ();
2015-11-16 14:37:51 +01:00
if ( ftruncate ( infos_file_descriptor , file_size ) < 0 )
{
obi_set_errno ( OBIDMS_UNKNOWN_ERROR );
2018-10-07 18:53:25 +02:00
obidebug ( 1 , " \n Error truncating a DMS information file to the right size" );
2015-11-16 14:37:51 +01:00
close ( infos_file_descriptor );
return - 1 ;
}
2018-10-07 18:53:25 +02:00
// Map the DMS infos structure
OBIDMS_infos_p infos = mmap ( NULL ,
file_size ,
PROT_READ | PROT_WRITE ,
MAP_SHARED ,
infos_file_descriptor ,
0
);
// Initialize values
infos -> little_endian = obi_is_little_endian ();
infos -> file_size = file_size ;
infos -> used_size = 0 ;
2019-09-20 20:37:19 +02:00
infos -> working = false ;
2018-10-07 18:53:25 +02:00
infos -> comments [ 0 ] = '\0' ;
// Unmap the infos file
if ( munmap ( infos , file_size ) < 0 )
2015-11-16 14:37:51 +01:00
{
2018-10-07 18:53:25 +02:00
obi_set_errno ( OBIVIEW_ERROR );
obidebug ( 1 , " \n Error munmapping a DMS information file" );
2015-11-16 14:37:51 +01:00
return - 1 ;
}
2016-09-15 11:50:30 +02:00
if ( close ( infos_file_descriptor ) < 0 )
{
obi_set_errno ( OBIDMS_UNKNOWN_ERROR );
2018-10-07 18:53:25 +02:00
obidebug ( 1 , " \n Error closing a view file" );
2016-09-15 11:50:30 +02:00
return - 1 ;
}
2015-11-16 14:37:51 +01:00
return 0 ;
}
2017-10-16 10:35:07 +02:00
static int list_dms ( OBIDMS_p dms )
{
int i = 0 ;
2017-11-24 17:58:47 +01:00
while (( global_opened_dms_list [ i ] != NULL ) && ( global_opened_dms_list [ i ] != dms ))
2017-10-16 10:35:07 +02:00
i ++ ;
if ( i == ( MAX_NB_OPENED_DMS - 1 ))
{
obi_set_errno ( OBIDMS_UNKNOWN_ERROR );
obidebug ( 1 , " \n Error opening a DMS: maximum number of DMS opened by a program reached" );
return - 1 ;
}
2017-11-24 17:58:47 +01:00
if ( global_opened_dms_list [ i ] == NULL )
{ // new dms
global_opened_dms_list [ i ] = dms ;
2018-10-29 16:12:37 +01:00
global_opened_dms_counter_list [ i ] = 1 ;
2017-11-24 17:58:47 +01:00
}
else
{ // already opened dms
( global_opened_dms_counter_list [ i ]) ++ ;
}
2017-10-16 10:35:07 +02:00
return 0 ;
}
2017-11-24 17:58:47 +01:00
static int unlist_dms ( OBIDMS_p dms , bool force )
2017-10-16 10:35:07 +02:00
{
int i = 0 ;
2017-11-24 17:58:47 +01:00
while (( global_opened_dms_list [ i ] != dms ) && ( i <= MAX_NB_OPENED_DMS ))
2017-10-16 10:35:07 +02:00
i ++ ;
2017-11-24 17:58:47 +01:00
if ( i == MAX_NB_OPENED_DMS )
return - 1 ; // DMS not found
// If opened more than once, and the unlisting is not forced, decrement counter
if (( global_opened_dms_counter_list [ i ] > 1 ) && ( ! force ))
( global_opened_dms_counter_list [ i ]) -- ;
else
{ // If opened once or forced unlisting, delete and unlist by shifting the list
while ( global_opened_dms_list [ i ] != NULL )
{
global_opened_dms_list [ i ] = global_opened_dms_list [ i + 1 ];
i ++ ;
}
2017-10-16 10:35:07 +02:00
}
2017-11-24 17:58:47 +01:00
return 0 ;
}
static OBIDMS_p check_if_dms_in_list ( const char * full_dms_path )
{
int i = 0 ;
while (( i <= MAX_NB_OPENED_DMS ) && ( global_opened_dms_list [ i ] != NULL ) && ( strcmp ( global_opened_dms_list [ i ] -> directory_path , full_dms_path ) != 0 ))
i ++ ;
if ( i == MAX_NB_OPENED_DMS )
return NULL ; // DMS not found
if ( global_opened_dms_list [ i ] != NULL )
return global_opened_dms_list [ i ];
return NULL ;
}
static int dms_count_in_list ( OBIDMS_p dms )
{
int i = 0 ;
while (( i <= MAX_NB_OPENED_DMS ) && ( global_opened_dms_list [ i ] != dms ))
i ++ ;
if ( i == MAX_NB_OPENED_DMS )
return - 1 ; // DMS not found
return global_opened_dms_counter_list [ i ];
2017-10-16 10:35:07 +02:00
}
2015-06-23 18:35:34 +02:00
/**********************************************************************
2015-06-17 16:51:16 +02:00
*
2015-06-23 18:35:34 +02:00
* 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
2015-06-17 16:51:16 +02:00
*
2015-06-23 18:35:34 +02:00
**********************************************************************/
2015-06-17 16:51:16 +02:00
2019-09-20 20:37:19 +02:00
int obi_dms_is_clean ( OBIDMS_p dms )
{
int ret_val1 ;
int ret_val2 ;
ret_val1 = obi_dms_has_unfinished_views ( dms );
if ( ret_val1 < 0 )
return - 1 ;
ret_val2 = obi_dms_has_unfinished_columns ( dms );
if ( ret_val2 < 0 )
return - 1 ;
return ! ( ret_val1 || ret_val2 );
}
int obi_clean_dms ( const char * dms_path )
{
OBIDMS_p dms ;
dms = obi_open_dms ( dms_path , true );
if ( dms == NULL )
{
obidebug ( 1 , " \n Error opening a DMS before cleaning unfinished views and columns" );
return - 1 ;
}
// Currently done in obi_open_dms
// // Clean unfinished views
// if (obi_clean_unfinished_views(dms) < 0)
// {
// obidebug(1, "\nError cleaning unfinished views");
// return -1;
// }
//
// // Clean unfinished columns
// if (obi_clean_unfinished_columns(dms) < 0)
// {
// obidebug(1, "\nError cleaning unfinished columns");
// return -1;
// }
2020-01-18 17:27:35 +01:00
if ( obi_close_dms ( dms , true ) < 0 )
{
obidebug ( 1 , " \n Error closing a DMS after cleaning" );
return - 1 ;
}
2019-09-20 20:37:19 +02:00
return 0 ;
}
2016-04-29 17:46:36 +02:00
int obi_dms_exists ( const char * dms_path )
2015-06-17 16:51:16 +02:00
{
2015-05-26 21:36:55 +02:00
struct stat buffer ;
2016-02-18 10:38:51 +01:00
char * directory_name ;
int check_dir ;
2015-05-26 21:36:55 +02:00
// Build and check the directory name
2016-04-29 17:46:36 +02:00
directory_name = build_directory_name ( dms_path );
2015-06-17 16:51:16 +02:00
if ( directory_name == NULL )
2015-05-26 21:36:55 +02:00
return - 1 ;
2015-06-23 18:35:34 +02:00
check_dir = stat ( directory_name , & buffer );
2015-05-26 21:36:55 +02:00
2015-06-17 16:51:16 +02:00
free ( directory_name );
2015-05-26 21:36:55 +02:00
2015-06-23 18:35:34 +02:00
if ( check_dir == 0 )
2015-05-26 21:36:55 +02:00
return 1 ;
2015-06-23 18:35:34 +02:00
else
return 0 ;
2015-05-26 21:36:55 +02:00
}
2016-04-29 17:46:36 +02:00
OBIDMS_p obi_create_dms ( const char * dms_path )
2015-06-17 16:51:16 +02:00
{
2018-10-07 18:53:25 +02:00
char * directory_name ;
DIR * dms_dir ;
int dms_file_descriptor ;
OBIDMS_p dms ;
2015-05-23 16:29:06 +03:00
// Build and check the directory name
2016-04-29 17:46:36 +02:00
directory_name = build_directory_name ( dms_path );
2015-06-17 16:51:16 +02:00
if ( directory_name == NULL )
2015-05-23 16:29:06 +03:00
return NULL ;
// Try to create the directory
2015-09-21 15:48:02 +02:00
if ( mkdir ( directory_name , 00777 ) < 0 )
2015-05-23 16:29:06 +03:00
{
2015-06-17 16:51:16 +02:00
if ( errno == EEXIST )
2015-11-09 15:22:01 +01:00
{
2015-05-23 16:29:06 +03:00
obi_set_errno ( OBIDMS_EXIST_ERROR );
2015-11-09 15:22:01 +01:00
obidebug ( 1 , " \n An OBIDMS directory with the same name already exists in this directory." );
}
2015-05-23 16:29:06 +03:00
else
obi_set_errno ( OBIDMS_UNKNOWN_ERROR );
2015-08-03 15:10:39 +02:00
obidebug ( 1 , " \n Problem creating an OBIDMS directory" );
2015-06-17 16:51:16 +02:00
free ( directory_name );
2015-05-23 16:29:06 +03:00
return NULL ;
}
2016-06-30 11:41:30 +02:00
// Get file descriptor of DMS directory to create other directories
2015-11-03 14:22:00 +01:00
dms_dir = opendir ( directory_name );
if ( dms_dir == NULL )
{
obi_set_errno ( OBIDMS_UNKNOWN_ERROR );
obidebug ( 1 , " \n Problem opening a newly created OBIDMS directory" );
free ( directory_name );
return NULL ;
}
2015-11-09 11:22:51 +01:00
free ( directory_name );
2015-11-03 14:22:00 +01:00
dms_file_descriptor = dirfd ( dms_dir );
if ( dms_file_descriptor < 0 )
{
obi_set_errno ( OBIDMS_UNKNOWN_ERROR );
obidebug ( 1 , " \n Problem getting the file descriptor of a newly created OBIDMS directory" );
return NULL ;
}
2016-04-12 14:53:33 +02:00
// Create the indexer directory
if ( mkdirat ( dms_file_descriptor , INDEXER_DIR_NAME , 00777 ) < 0 )
2015-11-03 14:22:00 +01:00
{
2016-04-12 14:53:33 +02:00
obi_set_errno ( OBI_INDEXER_ERROR );
2016-10-10 17:02:51 +02:00
obidebug ( 1 , " \n Problem creating the indexer directory" );
2015-11-03 14:22:00 +01:00
return NULL ;
}
2016-06-30 11:41:30 +02:00
// Create the view directory
if ( mkdirat ( dms_file_descriptor , VIEW_DIR_NAME , 00777 ) < 0 )
{
obi_set_errno ( OBIVIEW_ERROR );
2016-10-10 17:02:51 +02:00
obidebug ( 1 , " \n Problem creating the view directory" );
return NULL ;
}
// Create the taxonomy directory
if ( mkdirat ( dms_file_descriptor , TAXONOMY_DIR_NAME , 00777 ) < 0 )
{
obi_set_errno ( OBIVIEW_ERROR );
obidebug ( 1 , " \n Problem creating the taxonomy directory" );
2016-06-30 11:41:30 +02:00
return NULL ;
}
2018-10-07 18:53:25 +02:00
// Create the information file
2017-08-20 17:25:58 +02:00
if ( create_dms_infos_file ( dms_file_descriptor , basename (( char * ) dms_path )) < 0 )
2015-11-16 14:37:51 +01:00
return NULL ;
2018-10-07 18:53:25 +02:00
// Open DMS
2019-09-20 20:37:19 +02:00
dms = obi_open_dms ( dms_path , false );
2018-10-07 18:53:25 +02:00
if ( dms == NULL )
{
obidebug ( 1 , " \n Problem opening a DMS" );
return NULL ;
}
// Write empty json string in comments (Python json lib doesn't like empty "")
if ( obi_dms_write_comments ( dms , "{}" ) < 0 )
{
obidebug ( 1 , " \n Problem initializing empty json string in new DMS comments" );
return NULL ;
}
2019-08-29 16:35:10 +02:00
if ( closedir ( dms_dir ) < 0 )
{
obi_set_errno ( OBIDMS_UNKNOWN_ERROR );
obidebug ( 1 , " \n Error closing a directory" );
return NULL ;
}
2018-10-07 18:53:25 +02:00
return dms ;
2015-05-23 16:29:06 +03:00
}
2015-06-10 15:19:02 +02:00
2019-09-20 20:37:19 +02:00
OBIDMS_p obi_open_dms ( const char * dms_path , bool cleaning )
2015-06-17 16:51:16 +02:00
{
OBIDMS_p dms ;
2017-11-24 17:58:47 +01:00
char * relative_dms_path ;
char * absolute_dms_path ;
2019-09-25 11:38:00 +02:00
//int clean_dms;
2015-06-17 16:51:16 +02:00
dms = NULL ;
2015-05-23 16:29:06 +03:00
2017-11-24 17:58:47 +01:00
// Build and check the directory name including the relative path
relative_dms_path = build_directory_name ( dms_path );
if ( relative_dms_path == NULL )
return NULL ;
// Get and store the absolute path to the DMS directory
absolute_dms_path = realpath ( relative_dms_path , NULL );
if ( absolute_dms_path == NULL )
{
obi_set_errno ( OBIDMS_UNKNOWN_ERROR );
obidebug ( 1 , " \n Error getting the absolute path to the DMS directory (DMS does not exist)" );
free ( relative_dms_path );
return NULL ;
}
free ( relative_dms_path );
// Check if the DMS is already opened
dms = check_if_dms_in_list ( absolute_dms_path );
if ( dms != NULL )
{
list_dms ( dms );
free ( absolute_dms_path );
return dms ;
}
2015-11-09 15:06:02 +01:00
// Allocate the data structure
dms = ( OBIDMS_p ) malloc ( sizeof ( OBIDMS_t ));
if ( dms == NULL )
{
obi_set_errno ( OBIDMS_MEMORY_ERROR );
obidebug ( 1 , " \n Error allocating the memory for the OBIDMS structure" );
return NULL ;
}
2017-08-20 17:25:58 +02:00
strcpy ( dms -> dms_name , basename (( char * ) dms_path ));
2017-11-24 17:58:47 +01:00
strcpy ( dms -> directory_path , absolute_dms_path );
2016-08-29 17:30:31 +02:00
2015-06-23 18:35:34 +02:00
// Try to open the directory
2016-04-29 17:46:36 +02:00
dms -> directory = opendir ( dms -> directory_path );
2015-11-09 15:06:02 +01:00
if ( dms -> directory == NULL )
2015-06-23 18:35:34 +02:00
{
switch ( errno )
{
case ENOENT :
obi_set_errno ( OBIDMS_NOT_EXIST_ERROR );
break ;
2015-05-23 16:29:06 +03:00
2015-06-23 18:35:34 +02:00
case EACCES :
obi_set_errno ( OBIDMS_ACCESS_ERROR );
break ;
2015-05-23 16:29:06 +03:00
2015-06-23 18:35:34 +02:00
case ENOMEM :
obi_set_errno ( OBIDMS_MEMORY_ERROR );
break ;
2015-05-23 16:29:06 +03:00
2015-06-23 18:35:34 +02:00
default :
obi_set_errno ( OBIDMS_UNKNOWN_ERROR );
2015-05-23 16:29:06 +03:00
}
2015-08-03 15:10:39 +02:00
obidebug ( 1 , " \n Can't open OBIDMS directory" );
2015-11-09 15:06:02 +01:00
free ( dms );
2015-05-23 16:29:06 +03:00
return NULL ;
}
2018-10-07 18:53:25 +02:00
// Get and store file descriptor of DMS directory
2015-11-09 15:06:02 +01:00
dms -> dir_fd = dirfd ( dms -> directory );
if ( dms -> dir_fd < 0 )
2015-11-03 14:22:00 +01:00
{
obi_set_errno ( OBIDMS_UNKNOWN_ERROR );
obidebug ( 1 , " \n Error getting the file descriptor for a newly created OBIDMS directory" );
2015-11-09 15:06:02 +01:00
closedir ( dms -> directory );
free ( dms );
2015-11-03 14:22:00 +01:00
return NULL ;
}
2018-10-07 18:53:25 +02:00
// Open the information file
dms -> infos = map_infos_file ( dms -> dir_fd , dms -> dms_name );
if ( dms -> infos == NULL )
2015-11-16 14:37:51 +01:00
{
2018-10-07 18:53:25 +02:00
obidebug ( 1 , " \n Error opening a DMS information file" );
2015-11-16 14:37:51 +01:00
closedir ( dms -> directory );
free ( dms );
return NULL ;
}
2019-09-20 20:37:19 +02:00
// Reset the working variable to false if cleaning the DMS
if ( cleaning )
( dms -> infos ) -> working = false ;
// Check that the DMS is not already working (being used by a process)
if (( dms -> infos ) -> working )
{
obidebug ( 1 , " \n\n ERROR: \n The DMS '%s' contains unfinished views or columns. Either another command is currently running, "
"in which case you have to wait for it to finish, or a previous command was interrupted, "
"in which case you can run 'obi clean_dms [your_dms]' to clean the DMS. \n " , dms -> dms_name );
obi_set_errno ( OBIDMS_WORKING );
unmap_infos_file ( dms );
closedir ( dms -> directory );
free ( dms );
return NULL ;
}
// Set the working variable to true
( dms -> infos ) -> working = true ;
2016-04-12 14:53:33 +02:00
// Open the indexer directory
dms -> indexer_directory = opendir_in_dms ( dms , INDEXER_DIR_NAME );
if ( dms -> indexer_directory == NULL )
2015-11-03 14:22:00 +01:00
{
obi_set_errno ( OBIDMS_UNKNOWN_ERROR );
2016-04-12 14:53:33 +02:00
obidebug ( 1 , " \n Error opening the indexer directory" );
2018-10-07 18:53:25 +02:00
unmap_infos_file ( dms );
2015-11-09 15:06:02 +01:00
closedir ( dms -> directory );
free ( dms );
2015-11-03 14:22:00 +01:00
return NULL ;
}
2016-04-12 14:53:33 +02:00
// Store the indexer directory's file descriptor
dms -> indexer_dir_fd = dirfd ( dms -> indexer_directory );
if ( dms -> indexer_dir_fd < 0 )
2015-11-09 15:06:02 +01:00
{
obi_set_errno ( OBIDMS_UNKNOWN_ERROR );
2016-04-12 14:53:33 +02:00
obidebug ( 1 , " \n Error getting the file descriptor of the indexer directory" );
2018-10-07 18:53:25 +02:00
unmap_infos_file ( dms );
2016-04-12 14:53:33 +02:00
closedir ( dms -> indexer_directory );
2015-11-16 14:37:51 +01:00
closedir ( dms -> directory );
2015-11-09 15:06:02 +01:00
free ( dms );
return NULL ;
}
2015-06-23 18:35:34 +02:00
2016-06-30 11:41:30 +02:00
// Open the view directory
dms -> view_directory = opendir_in_dms ( dms , VIEW_DIR_NAME );
if ( dms -> view_directory == NULL )
{
obi_set_errno ( OBIDMS_UNKNOWN_ERROR );
obidebug ( 1 , " \n Error opening the view directory" );
2018-10-07 18:53:25 +02:00
unmap_infos_file ( dms );
2016-06-30 11:41:30 +02:00
closedir ( dms -> indexer_directory );
closedir ( dms -> directory );
free ( dms );
return NULL ;
}
// Store the view directory's file descriptor
dms -> view_dir_fd = dirfd ( dms -> view_directory );
if ( dms -> view_dir_fd < 0 )
{
obi_set_errno ( OBIDMS_UNKNOWN_ERROR );
obidebug ( 1 , " \n Error getting the file descriptor of the view directory" );
2018-10-07 18:53:25 +02:00
unmap_infos_file ( dms );
2016-06-30 11:41:30 +02:00
closedir ( dms -> view_directory );
closedir ( dms -> directory );
free ( dms );
return NULL ;
}
2016-10-14 17:03:10 +02:00
// Open the taxonomy directory
dms -> tax_directory = opendir_in_dms ( dms , TAXONOMY_DIR_NAME );
if ( dms -> tax_directory == NULL )
{
obi_set_errno ( OBIDMS_UNKNOWN_ERROR );
obidebug ( 1 , " \n Error opening the taxonomy directory" );
2018-10-07 18:53:25 +02:00
unmap_infos_file ( dms );
2016-10-14 17:03:10 +02:00
closedir ( dms -> indexer_directory );
closedir ( dms -> view_directory );
closedir ( dms -> directory );
free ( dms );
return NULL ;
}
// Store the taxonomy directory's file descriptor
dms -> tax_dir_fd = dirfd ( dms -> tax_directory );
if ( dms -> tax_dir_fd < 0 )
{
obi_set_errno ( OBIDMS_UNKNOWN_ERROR );
obidebug ( 1 , " \n Error getting the file descriptor of the taxonomy directory" );
2018-10-07 18:53:25 +02:00
unmap_infos_file ( dms );
2016-10-14 17:03:10 +02:00
closedir ( dms -> indexer_directory );
2017-10-26 18:58:48 +02:00
closedir ( dms -> tax_directory );
closedir ( dms -> view_directory );
closedir ( dms -> directory );
free ( dms );
return NULL ;
}
2019-09-20 20:37:19 +02:00
// // Check for unfinished views and columns
// clean_dms = obi_dms_is_clean(dms);
// if (clean_dms < 0)
// {
// obi_set_errno(OBIDMS_UNKNOWN_ERROR);
// obidebug(1, "\nError checking if a DMS has unfinished views or columns when opening it");
// unmap_infos_file(dms);
// closedir(dms->indexer_directory);
// closedir(dms->tax_directory);
// closedir(dms->view_directory);
// closedir(dms->directory);
// free(dms);
// return NULL;
// }
// if (! clean_dms)
// obi_set_errno(OBIDMS_NOT_CLEAN);
2017-10-26 18:58:48 +02:00
// Clean unfinished views
if ( obi_clean_unfinished_views ( dms ) < 0 )
{
obidebug ( 1 , " \n Error cleaning unfinished views when opening an OBIDMS" );
2018-10-07 18:53:25 +02:00
unmap_infos_file ( dms );
2017-10-26 18:58:48 +02:00
closedir ( dms -> indexer_directory );
closedir ( dms -> tax_directory );
closedir ( dms -> view_directory );
closedir ( dms -> directory );
free ( dms );
return NULL ;
}
// Clean unfinished columns
if ( obi_clean_unfinished_columns ( dms ) < 0 )
{
obidebug ( 1 , " \n Error cleaning unfinished columns when opening an OBIDMS" );
2018-10-07 18:53:25 +02:00
unmap_infos_file ( dms );
2017-10-26 18:58:48 +02:00
closedir ( dms -> indexer_directory );
2016-10-14 17:03:10 +02:00
closedir ( dms -> tax_directory );
closedir ( dms -> view_directory );
closedir ( dms -> directory );
free ( dms );
return NULL ;
}
2015-12-02 17:32:07 +01:00
// Initialize the list of opened columns
dms -> opened_columns = ( Opened_columns_list_p ) malloc ( sizeof ( Opened_columns_list_t ));
( dms -> opened_columns ) -> nb_opened_columns = 0 ;
2016-04-22 11:28:09 +02:00
// Initialize the list of opened indexers
2016-04-12 14:53:33 +02:00
dms -> opened_indexers = ( Opened_indexers_list_p ) malloc ( sizeof ( Opened_indexers_list_t ));
( dms -> opened_indexers ) -> nb_opened_indexers = 0 ;
2015-12-02 17:32:07 +01:00
2017-10-16 10:35:07 +02:00
// Add in the global list of opened DMS
2017-11-24 17:58:47 +01:00
if ( list_dms ( dms ) < 0 )
{
obidebug ( 1 , " \n Error cleaning unfinished columns when opening an OBIDMS" );
2018-10-07 18:53:25 +02:00
unmap_infos_file ( dms );
2017-11-24 17:58:47 +01:00
closedir ( dms -> indexer_directory );
closedir ( dms -> tax_directory );
closedir ( dms -> view_directory );
closedir ( dms -> directory );
free ( dms -> opened_columns );
free ( dms -> opened_indexers );
free ( dms );
return NULL ;
}
2017-10-16 10:35:07 +02:00
2015-05-23 16:29:06 +03:00
return dms ;
}
2015-06-10 15:19:02 +02:00
2017-07-05 15:38:22 +02:00
OBIDMS_p obi_test_open_dms ( const char * dms_name )
{
int exists ;
exists = obi_dms_exists ( dms_name );
switch ( exists )
{
case 0 :
return NULL ;
case 1 :
2019-09-20 20:37:19 +02:00
return obi_open_dms ( dms_name , false );
2017-07-05 15:38:22 +02:00
};
obidebug ( 1 , " \n Error checking if an OBIDMS directory exists" );
return NULL ;
}
2015-06-17 16:51:16 +02:00
OBIDMS_p obi_dms ( const char * dms_name )
{
2015-06-23 18:35:34 +02:00
int exists ;
2015-05-26 21:36:55 +02:00
2015-06-23 18:35:34 +02:00
exists = obi_dms_exists ( dms_name );
switch ( exists )
{
2015-05-26 21:36:55 +02:00
case 0 :
2015-06-17 16:51:16 +02:00
return obi_create_dms ( dms_name );
2015-05-26 21:36:55 +02:00
case 1 :
2019-09-20 20:37:19 +02:00
return obi_open_dms ( dms_name , false );
2015-05-26 21:36:55 +02:00
};
2015-08-03 15:10:39 +02:00
obidebug ( 1 , " \n Error checking if an OBIDMS directory exists" );
2015-05-26 21:36:55 +02:00
return NULL ;
}
2015-05-23 16:29:06 +03:00
2017-11-24 17:58:47 +01:00
int obi_close_dms ( OBIDMS_p dms , bool force )
2015-06-17 16:51:16 +02:00
{
2017-11-24 17:58:47 +01:00
int dms_counter ;
if ( ! force )
{
dms_counter = dms_count_in_list ( dms );
if ( dms_counter < 0 )
obidebug ( 1 , " \n Error checking the counter of an OBIDMS in the global list of opened OBIDMS" );
if ( dms_counter > 1 ) // Don't close if the DMS is opened more than once
{
if ( unlist_dms ( dms , force ) < 0 )
{
obidebug ( 1 , " \n Error decrementing the counter of an OBIDMS in the global list of opened OBIDMS" );
return - 1 ;
}
return 0 ;
}
}
2015-05-23 16:29:06 +03:00
if ( dms != NULL )
{
2015-12-02 17:32:07 +01:00
// Close all columns
while (( dms -> opened_columns ) -> nb_opened_columns > 0 )
obi_close_column ( * (( dms -> opened_columns ) -> columns ));
2016-10-14 17:03:10 +02:00
// Close dms, and view, indexer and taxonomy directories
2016-04-22 11:28:09 +02:00
if ( closedir ( dms -> indexer_directory ) < 0 )
2015-11-03 14:22:00 +01:00
{
2016-04-12 14:53:33 +02:00
obi_set_errno ( OBI_INDEXER_ERROR );
obidebug ( 1 , " \n Error closing an indexer directory" );
2015-05-23 16:29:06 +03:00
free ( dms );
return - 1 ;
}
2016-06-30 11:41:30 +02:00
if ( closedir ( dms -> view_directory ) < 0 )
{
obi_set_errno ( OBIVIEW_ERROR );
obidebug ( 1 , " \n Error closing a view directory" );
free ( dms );
return - 1 ;
}
2016-10-14 17:03:10 +02:00
if ( closedir ( dms -> tax_directory ) < 0 )
{
obi_set_errno ( OBIVIEW_ERROR );
obidebug ( 1 , " \n Error closing a taxonomy directory" );
free ( dms );
return - 1 ;
}
2019-09-20 20:37:19 +02:00
// Set the working variable as false
( dms -> infos ) -> working = false ;
// Unmap information file
if ( unmap_infos_file ( dms ) < 0 )
{
obidebug ( 1 , " \n Error unmaping a DMS information file while closing a DMS" );
free ( dms );
return - 1 ;
}
2016-09-15 11:50:30 +02:00
if ( closedir ( dms -> directory ) < 0 )
{
obi_set_errno ( OBIDMS_MEMORY_ERROR );
obidebug ( 1 , " \n Error closing an OBIDMS directory" );
free ( dms );
return - 1 ;
}
2017-10-16 10:35:07 +02:00
// Remove DMS from global list of opened DMS
2017-11-24 17:58:47 +01:00
if ( unlist_dms ( dms , force ) < 0 )
{
obidebug ( 1 , " \n Error removing an OBIDMS from the global list of opened OBIDMS when closing it" );
free ( dms );
return - 1 ;
}
2017-10-16 10:35:07 +02:00
2015-05-23 16:29:06 +03:00
free ( dms );
}
return 0 ;
}
2016-04-15 10:49:12 +02:00
2018-10-07 18:53:25 +02:00
int obi_dms_write_comments ( OBIDMS_p dms , const char * comments )
{
size_t new_size ;
if ( comments == NULL )
return 0 ; // TODO or error? discuss
new_size = sizeof ( OBIDMS_infos_t ) + strlen ( comments ) + 1 ;
// Check if the file has to be enlarged
if ( new_size >= ( dms -> infos ) -> file_size )
{
if ( enlarge_infos_file ( dms , new_size ) < 0 )
return - 1 ;
}
strcpy (( dms -> infos ) -> comments , comments );
( dms -> infos ) -> used_size = new_size ;
return 0 ;
}
int obi_dms_add_comment ( OBIDMS_p dms , const char * key , const char * value )
{
char * new_comments = NULL ;
new_comments = obi_add_comment (( dms -> infos ) -> comments , key , value );
if ( new_comments == NULL )
{
obidebug ( 1 , " \n Error adding a comment to a dms, key: %s, value: %s" , key , value );
return - 1 ;
}
if ( obi_dms_write_comments ( dms , new_comments ) < 0 )
{
obidebug ( 1 , " \n Error adding a comment to a dms, key: %s, value: %s" , key , value );
return - 1 ;
}
free ( new_comments );
return 0 ;
}
2016-04-15 10:49:12 +02:00
OBIDMS_column_p obi_dms_get_column_from_list ( OBIDMS_p dms , const char * column_name , obiversion_t version )
{
int i ;
for ( i = 0 ; i < (( dms -> opened_columns ) -> nb_opened_columns ); i ++ )
{
if ( ! strcmp ((( * ((( dms -> opened_columns ) -> columns ) + i )) -> header ) -> name , column_name )
&& ((( * ((( dms -> opened_columns ) -> columns ) + i )) -> header ) -> version == version ))
{ // Found the column already opened, return it
return * ((( dms -> opened_columns ) -> columns ) + i );
}
}
// Didn't find the column
return NULL ;
}
2016-04-22 11:28:09 +02:00
void obi_dms_list_column ( OBIDMS_p dms , OBIDMS_column_p column ) // TODO add check if column already in list?
2016-04-15 10:49:12 +02:00
{
* ((( dms -> opened_columns ) -> columns ) + (( dms -> opened_columns ) -> nb_opened_columns )) = column ;
(( dms -> opened_columns ) -> nb_opened_columns ) ++ ;
}
int obi_dms_unlist_column ( OBIDMS_p dms , OBIDMS_column_p column )
{
int i ;
Opened_columns_list_p columns_list ;
columns_list = dms -> opened_columns ;
for ( i = 0 ; i < columns_list -> nb_opened_columns ; i ++ )
{
if ( ! strcmp ((( * (( columns_list -> columns ) + i )) -> header ) -> name , ( column -> header ) -> name )
&& ((( * (( columns_list -> columns ) + i )) -> header ) -> version == ( column -> header ) -> version ))
{ // Found the column. Rearrange list
( columns_list -> nb_opened_columns ) -- ;
( columns_list -> columns )[ i ] = ( columns_list -> columns )[ columns_list -> nb_opened_columns ];
return 0 ;
}
}
obidebug ( 1 , " \n Could not find the column to delete from list of open columns" );
return - 1 ;
}
Obi_indexer_p obi_dms_get_indexer_from_list ( OBIDMS_p dms , const char * indexer_name )
{
int i ;
Opened_indexers_list_p indexers_list ;
indexers_list = dms -> opened_indexers ;
for ( i = 0 ; i < ( indexers_list -> nb_opened_indexers ); i ++ )
{
2016-04-29 16:18:56 +02:00
if ( ! strcmp ( obi_indexer_get_name (( indexers_list -> indexers )[ i ]), indexer_name ))
2016-04-15 10:49:12 +02:00
{ // Found the indexer already opened, return it
return ( indexers_list -> indexers )[ i ];
}
}
// Didn't find the indexer
return NULL ;
}
2016-04-29 16:06:01 +02:00
void obi_dms_list_indexer ( OBIDMS_p dms , Obi_indexer_p indexer ) // TODO add check if indexer already in list?
2016-04-15 10:49:12 +02:00
{
* ((( dms -> opened_indexers ) -> indexers ) + (( dms -> opened_indexers ) -> nb_opened_indexers )) = indexer ;
(( dms -> opened_indexers ) -> nb_opened_indexers ) ++ ;
}
int obi_dms_unlist_indexer ( OBIDMS_p dms , Obi_indexer_p indexer )
{
int i ;
Opened_indexers_list_p indexers_list ;
indexers_list = dms -> opened_indexers ;
for ( i = 0 ; i < indexers_list -> nb_opened_indexers ; i ++ )
{
2016-04-29 16:18:56 +02:00
if ( ! strcmp ( obi_indexer_get_name (( indexers_list -> indexers )[ i ]), indexer -> name ))
2016-04-15 10:49:12 +02:00
{ // Found the indexer. Rearrange list
( indexers_list -> nb_opened_indexers ) -- ;
( indexers_list -> indexers )[ i ] = ( indexers_list -> indexers )[ indexers_list -> nb_opened_indexers ];
return 0 ;
}
}
obidebug ( 1 , " \n Could not find the indexer to delete from list of open indexers" );
return - 1 ;
}
2016-04-15 11:11:13 +02:00
char * obi_dms_get_dms_path ( OBIDMS_p dms )
2016-04-15 10:49:12 +02:00
{
char * full_path ;
full_path = ( char * ) malloc (( MAX_PATH_LEN ) * sizeof ( char ));
if ( full_path == NULL )
{
obi_set_errno ( OBI_MALLOC_ERROR );
obidebug ( 1 , " \n Error allocating memory for the char* path to a file or directory" );
return NULL ;
}
2016-04-29 17:46:36 +02:00
strcpy ( full_path , dms -> directory_path );
2016-04-15 11:11:13 +02:00
return full_path ;
}
char * obi_dms_get_full_path ( OBIDMS_p dms , const char * path_name )
{
char * full_path ;
full_path = obi_dms_get_dms_path ( dms );
2016-04-15 10:49:12 +02:00
strcat ( full_path , "/" );
strcat ( full_path , path_name );
return full_path ;
}
DIR * opendir_in_dms ( OBIDMS_p dms , const char * path_name )
{
char * full_path ;
DIR * directory ;
2016-04-15 11:11:13 +02:00
full_path = obi_dms_get_full_path ( dms , path_name );
2016-04-15 10:49:12 +02:00
if ( full_path == NULL )
return NULL ;
directory = opendir ( full_path );
if ( directory == NULL )
{
obi_set_errno ( OBI_UTILS_ERROR );
obidebug ( 1 , " \n Error opening a directory" );
}
free ( full_path );
return directory ;
}
2017-08-03 16:33:12 +02:00
2020-09-29 17:51:39 +02:00
char * obi_dms_formatted_infos ( OBIDMS_p dms , bool detailed )
{
char * dms_infos = NULL ;
char * view_infos = NULL ;
char * view_name = NULL ;
char * tax_name = NULL ;
char * all_tax_dir_path = NULL ;
2021-08-05 11:31:24 +12:00
int i , last_dot_pos ;
2020-09-29 17:51:39 +02:00
struct dirent * dp ;
Obiview_p view ;
// DMS name
dms_infos = ( char * ) malloc (( strlen ( "# DMS name: " ) + strlen ( dms -> dms_name ) + strlen ( " \n # Views: \n " ) + 1 ) * sizeof ( char ));
if ( dms_infos == NULL )
{
obidebug ( 1 , " \n Error allocating memory for DMS formatted infos" );
return NULL ;
}
strcpy ( dms_infos , "# DMS name: " );
strcat ( dms_infos , dms -> dms_name );
strcat ( dms_infos , " \n # Views: \n " );
// Go through views and get their infos
rewinddir ( dms -> view_directory );
while (( dp = readdir ( dms -> view_directory )) != NULL )
{
if (( dp -> d_name )[ 0 ] == '.' )
continue ;
i = 0 ;
2021-08-05 11:31:24 +12:00
while ( i < strlen ( dp -> d_name ))
{
if (( dp -> d_name )[ i ] == '.' )
last_dot_pos = i ;
2020-09-29 17:51:39 +02:00
i ++ ;
2021-08-05 11:31:24 +12:00
}
view_name = ( char * ) malloc (( last_dot_pos + 1 ) * sizeof ( char ));
2020-09-29 17:51:39 +02:00
if ( view_name == NULL )
{
obi_set_errno ( OBI_MALLOC_ERROR );
obidebug ( 1 , " \n Error allocating memory for a view name when getting formatted DMS infos: file %s" , dp -> d_name );
return NULL ;
}
2021-08-05 11:31:24 +12:00
strncpy ( view_name , dp -> d_name , last_dot_pos );
view_name [ last_dot_pos ] = '\0' ;
2020-09-29 17:51:39 +02:00
view = obi_open_view ( dms , view_name );
if ( view == NULL )
{
obidebug ( 1 , " \n Error opening a view to get DMS formatted infos" );
return NULL ;
}
if ( detailed )
view_infos = obi_view_formatted_infos ( view , detailed );
else
view_infos = obi_view_formatted_infos_one_line ( view );
if ( view_infos == NULL )
{
obidebug ( 1 , " \n Error getting a view infos to get DMS formatted infos" );
return NULL ;
}
dms_infos = realloc ( dms_infos , ( strlen ( dms_infos ) + strlen ( view_infos ) + 1 ) * sizeof ( char ));
if ( dms_infos == NULL )
{
obidebug ( 1 , " \n Error reallocating memory for DMS formatted infos" );
return NULL ;
}
strcat ( dms_infos , view_infos );
if ( obi_save_and_close_view ( view ) < 0 )
{
obidebug ( 1 , " \n Error closing view while getting DMS formatted infos" );
return NULL ;
}
if ( detailed )
{
dms_infos = realloc ( dms_infos , ( strlen ( dms_infos ) + 2 ) * sizeof ( char ));
strcat ( dms_infos , " \n " );
}
}
// Add taxonomies
dms_infos = realloc ( dms_infos , ( strlen ( dms_infos ) + strlen ( " \n # Taxonomies: \n " ) + 1 ) * sizeof ( char ));
if ( dms_infos == NULL )
{
obidebug ( 1 , " \n Error reallocating memory for DMS formatted infos" );
return NULL ;
}
strcat ( dms_infos , "# Taxonomies: \n " );
rewinddir ( dms -> tax_directory );
while (( dp = readdir ( dms -> tax_directory )) != NULL )
{
if (( dp -> d_name )[ 0 ] == '.' )
continue ;
tax_name = dp -> d_name ;
dms_infos = realloc ( dms_infos , ( strlen ( dms_infos ) + strlen ( " # " ) + strlen ( view_infos ) + 1 ) * sizeof ( char ));
if ( dms_infos == NULL )
{
obidebug ( 1 , " \n Error reallocating memory for DMS formatted infos" );
return NULL ;
}
strcat ( dms_infos , " # " );
strcat ( dms_infos , tax_name );
}
return dms_infos ;
}
2017-08-03 16:33:12 +02:00
// TODO move somewhere else maybe
// TODO discuss arguments
obiversion_t obi_import_column ( const char * dms_path_1 , const char * dms_path_2 , const char * column_name , obiversion_t version_number )
{
OBIDMS_p dms_1 ;
OBIDMS_p dms_2 ;
OBIDMS_column_p column_1 ;
OBIDMS_column_p column_2 ;
OBIDMS_column_header_p header_1 ;
OBIDMS_column_header_p header_2 ;
int avl_exists ;
const char * avl_name ;
char * new_avl_name ;
obiversion_t new_version ;
int i ;
int avl_count ;
char * avl_name_1 ;
char * avl_name_2 ;
char * avl_file_path_1 ;
char * avl_file_path_2 ;
char * avl_data_file_path_1 ;
char * avl_data_file_path_2 ;
char * complete_avl_name ;
Obi_indexer_p avl_group ;
2019-09-20 20:37:19 +02:00
dms_1 = obi_open_dms ( dms_path_1 , false );
2017-08-03 16:33:12 +02:00
if ( dms_1 == NULL )
{
obidebug ( 1 , " \n Error opening a DMS to import a column from it" );
return - 1 ;
}
dms_2 = obi_dms ( dms_path_2 );
if ( dms_2 == NULL )
{
obidebug ( 1 , " \n Error opening or creating a DMS to import a column into it" );
return - 1 ;
}
column_1 = obi_open_column ( dms_1 , column_name , version_number );
if ( column_1 == NULL )
{
obidebug ( 1 , " \n Error opening a column to import in another DMS" );
return - 1 ;
}
header_1 = column_1 -> header ;
// Check if associated indexer exists BEFORE creating the new column as that will automatically create it if it doesn't already exist
avl_name = header_1 -> indexer_name ;
avl_exists = obi_indexer_exists ( dms_2 , avl_name );
if ( avl_exists == - 1 )
{
obidebug ( 1 , " \n Error checking if an indexer exists while importing a column" );
return - 1 ;
}
if ( avl_exists )
// Use automatic name
new_avl_name = NULL ;
else
// Name can stay the same
new_avl_name = header_1 -> indexer_name ;
// Create new column
column_2 = obi_create_column ( dms_2 , column_name , header_1 -> returned_data_type , header_1 -> line_count ,
2021-03-10 16:50:30 +13:00
header_1 -> nb_elements_per_line , header_1 -> elements_names , true , header_1 -> dict_column ,
header_1 -> tuples , header_1 -> to_eval , new_avl_name , ( header_1 -> associated_column ). column_name ,
2017-12-13 22:46:50 +01:00
( header_1 -> associated_column ). version , header_1 -> comments );
2017-08-03 16:33:12 +02:00
if ( column_2 == NULL )
{
obidebug ( 1 , " \n Error creating the new column while importing a column" );
return - 1 ;
}
header_2 = column_2 -> header ;
// Get the new version to return
new_version = header_2 -> version ;
// Copy lines_used informations
header_2 -> lines_used = header_1 -> lines_used ;
// Copy data TODO check how much time and memory that costs, eventually use write() instead
memcpy ( column_2 -> data , column_1 -> data , header_1 -> data_size );
// Copy the AVL files if there are some (overwriting the automatically created files)
2020-06-09 14:34:43 +02:00
if (( header_1 -> tuples ) || (( header_1 -> returned_data_type == OBI_STR ) || ( header_1 -> returned_data_type == OBI_SEQ ) || ( header_1 -> returned_data_type == OBI_QUAL )))
2017-08-03 16:33:12 +02:00
{
avl_name_1 = ( char * ) malloc (( strlen ( header_1 -> indexer_name ) + 1 ) * sizeof ( char ));
if ( avl_name_1 == NULL )
{
obi_set_errno ( OBI_MALLOC_ERROR );
obidebug ( 1 , " \n Error allocating memory for an AVL name when importing a column" );
return - 1 ;
}
strcpy ( avl_name_1 , header_1 -> indexer_name );
avl_name_2 = ( char * ) malloc (( strlen ( header_2 -> indexer_name ) + 1 ) * sizeof ( char ));
if ( avl_name_2 == NULL )
{
obi_set_errno ( OBI_MALLOC_ERROR );
obidebug ( 1 , " \n Error allocating memory for an AVL name when importing a column" );
return - 1 ;
}
strcpy ( avl_name_2 , header_2 -> indexer_name );
avl_count = ( column_1 -> indexer -> last_avl_idx ) + 1 ;
// Close column to manipulate AVL files safely (but not multithreading safe) (TODO not sure how important this is, can't find informations about conflicts when using write() on mmapped files)
if ( obi_close_column ( column_1 ) < 0 )
{
obidebug ( 1 , " \n Error closing an imported column" );
return - 1 ;
}
2018-10-29 17:39:30 +01:00
( column_2 -> header ) -> finished = true ; // note: this is normally handled by the view that created the column
2017-08-03 16:33:12 +02:00
if ( obi_close_column ( column_2 ) < 0 )
{
obidebug ( 1 , " \n Error closing an imported column" );
return - 1 ;
}
for ( i = 0 ; i < avl_count ; i ++ )
{
avl_file_path_1 = obi_get_full_path_of_avl_file_name ( dms_1 , avl_name_1 , i );
if ( avl_file_path_1 == NULL )
{
obidebug ( 1 , " \n Error getting an AVL file path while importing a column" );
return - 1 ;
}
avl_data_file_path_1 = obi_get_full_path_of_avl_data_file_name ( dms_1 , avl_name_1 , i );
if ( avl_data_file_path_1 == NULL )
{
obidebug ( 1 , " \n Error getting an AVL file path while importing a column" );
return - 1 ;
}
avl_file_path_2 = obi_get_full_path_of_avl_file_name ( dms_2 , avl_name_2 , i );
if ( avl_file_path_2 == NULL )
{
obidebug ( 1 , " \n Error getting an AVL file path while importing a column" );
return - 1 ;
}
avl_data_file_path_2 = obi_get_full_path_of_avl_data_file_name ( dms_2 , avl_name_2 , i );
if ( avl_data_file_path_2 == NULL )
{
obidebug ( 1 , " \n Error getting an AVL file path while importing a column" );
return - 1 ;
}
// Copy AVL file
if ( copy_file ( avl_file_path_1 , avl_file_path_2 ) < 0 )
{
obidebug ( 1 , " \n Error copying an AVL file while importing a column" );
return - 1 ;
}
// Copy AVL data file
if ( copy_file ( avl_data_file_path_1 , avl_data_file_path_2 ) < 0 )
{
obidebug ( 1 , " \n Error copying a data AVL file while importing a column" );
return - 1 ;
}
free ( avl_file_path_1 );
free ( avl_file_path_2 );
free ( avl_data_file_path_1 );
free ( avl_data_file_path_2 );
}
// Update AVL names in headers
avl_group = obi_open_indexer ( dms_2 , avl_name_2 );
for ( i = 0 ; i < avl_count ; i ++ )
{
complete_avl_name = obi_build_avl_name_with_idx ( avl_name_2 , i );
strcpy (((( avl_group -> sub_avls )[ i ]) -> header ) -> avl_name , complete_avl_name );
strcpy ((((( avl_group -> sub_avls )[ i ]) -> data ) -> header ) -> avl_name , complete_avl_name );
free ( complete_avl_name );
}
free ( avl_name_1 );
free ( avl_name_2 );
}
else
{
if ( obi_close_column ( column_1 ) < 0 )
{
obidebug ( 1 , " \n Error closing an imported column" );
return - 1 ;
}
2018-10-29 17:39:30 +01:00
( column_2 -> header ) -> finished = true ; // note: this is normally handled by the view that created the column
2017-08-03 16:33:12 +02:00
if ( obi_close_column ( column_2 ) < 0 )
{
obidebug ( 1 , " \n Error closing an imported column" );
return - 1 ;
}
}
// Copy associated column (update version)
//new_associated_col_version = import_column(dms_path_1, dms_path_2, header_1->associated_column_name, header_1->associated_column_version);
// TODO no? because if iterating over all columns in a view etc.... iterate and change associated columns version refs afterwards?
// Close the DMS
2017-11-24 17:58:47 +01:00
obi_close_dms ( dms_1 , false );
obi_close_dms ( dms_2 , false );
2017-08-03 16:33:12 +02:00
return new_version ;
}
// TODO move somewhere else maybe
// TODO discuss arguments
int obi_import_view ( const char * dms_path_1 , const char * dms_path_2 , const char * view_name_1 , const char * view_name_2 )
{
OBIDMS_p dms_1 ;
OBIDMS_p dms_2 ;
Obiview_p view_1 ;
Obiview_p view_2 ;
obiversion_t new_version ;
2018-11-07 13:35:11 +01:00
int i , j ;
OBIDMS_column_header_p header = NULL ;
OBIDMS_column_header_p header_2 = NULL ;
2017-08-03 16:33:12 +02:00
2019-09-21 16:47:22 +02:00
signal ( SIGINT , sig_handler );
2019-09-20 20:37:19 +02:00
dms_1 = obi_open_dms ( dms_path_1 , false );
2017-08-03 16:33:12 +02:00
if ( dms_1 == NULL )
{
obidebug ( 1 , " \n Error opening a DMS to import a view from it" );
return - 1 ;
}
dms_2 = obi_dms ( dms_path_2 );
if ( dms_2 == NULL )
{
obidebug ( 1 , " \n Error opening or creating a DMS to import a view into it" );
return - 1 ;
}
// Open view to import
view_1 = obi_open_view ( dms_1 , view_name_1 );
// Create new view
if ( strcmp (( view_1 -> infos ) -> view_type , VIEW_TYPE_NUC_SEQS ) == 0 )
2018-10-29 16:12:37 +01:00
view_2 = obi_new_view_nuc_seqs ( dms_2 , view_name_2 , NULL , NULL , ( view_1 -> infos ) -> comments , false , false );
2017-08-03 16:33:12 +02:00
else // Non-typed view
view_2 = obi_new_view ( dms_2 , view_name_2 , NULL , NULL , ( view_1 -> infos ) -> comments );
2020-07-26 17:39:55 +02:00
if ( view_2 == NULL )
{
obidebug ( 1 , " \n Error creating the new view to import a view in a DMS" );
return - 1 ;
}
2017-08-03 16:33:12 +02:00
// Import line count
view_2 -> infos -> line_count = view_1 -> infos -> line_count ;
// Import the line selection column if there is one
if ( ! view_1 -> infos -> all_lines )
{
view_2 -> infos -> all_lines = false ;
new_version = obi_import_column ( dms_path_1 , dms_path_2 , (( view_1 -> infos ) -> line_selection ). column_name , (( view_1 -> infos ) -> line_selection ). version );
if ( new_version == - 1 )
{
obidebug ( 1 , " \n Error importing a line selection column while importing a view" );
return - 1 ;
}
strcpy ((( view_2 -> infos ) -> line_selection ). column_name , (( view_1 -> infos ) -> line_selection ). column_name );
(( view_2 -> infos ) -> line_selection ). version = new_version ;
view_2 -> line_selection = obi_open_column ( dms_2 , (( view_2 -> infos ) -> line_selection ). column_name , (( view_2 -> infos ) -> line_selection ). version );
if ( view_2 -> line_selection == NULL )
{
obidebug ( 1 , " \n Error opening a line selection column while importing a view" );
return - 1 ;
}
}
// Import each column and update with the new version number
for ( i = 0 ; i < ( view_1 -> infos -> column_count ); i ++ )
{
2019-09-21 16:47:22 +02:00
if ( ! keep_running )
return - 1 ;
2017-08-03 16:33:12 +02:00
new_version = obi_import_column ( dms_path_1 , dms_path_2 , (((( view_1 -> infos ) -> column_references )[ i ]). column_refs ). column_name , (((( view_1 -> infos ) -> column_references )[ i ]). column_refs ). version );
if ( new_version == - 1 )
{
obidebug ( 1 , " \n Error importing a column while importing a view" );
return - 1 ;
}
if ( obi_view_add_column ( view_2 ,
(((( view_1 -> infos ) -> column_references )[ i ]). column_refs ). column_name ,
new_version ,
((( view_1 -> infos ) -> column_references )[ i ]). alias ,
0 ,
0 ,
0 ,
NULL ,
2017-11-15 13:48:59 +01:00
false ,
2017-12-13 22:46:50 +01:00
false ,
false ,
2021-03-10 16:50:30 +13:00
false ,
2017-08-03 16:33:12 +02:00
NULL ,
NULL ,
- 1 ,
NULL ,
false ) < 0 )
2018-10-29 16:12:37 +01:00
{
obidebug ( 1 , " \n Error adding a column to a view while importing it" );
return - 1 ;
}
2017-08-03 16:33:12 +02:00
}
2018-11-07 13:35:11 +01:00
// Go through columns again to update associated columns
for ( i = 0 ; i < ( view_1 -> infos -> column_count ); i ++ )
{
2019-09-21 16:47:22 +02:00
if ( ! keep_running )
return - 1 ;
2018-11-07 13:35:11 +01:00
header = obi_column_get_header_from_name ( dms_1 , (((( view_1 -> infos ) -> column_references )[ i ]). column_refs ). column_name , (((( view_1 -> infos ) -> column_references )[ i ]). column_refs ). version );
if ( header == NULL )
{
obidebug ( 1 , " \n Error opening a column header while importing a view" );
return - 1 ;
}
if ( header -> returned_data_type == OBI_QUAL ) // TODO maybe there should be a bool in column headers
{
// Look for the index of the associated column in the list
for ( j = 0 ; j < ( view_1 -> infos -> column_count ); j ++ )
{
if (( strcmp (( header -> associated_column ). column_name , (((( view_1 -> infos ) -> column_references )[ j ]). column_refs ). column_name ) == 0 ) &&
(( header -> associated_column ). version == (((( view_1 -> infos ) -> column_references )[ j ]). column_refs ). version ))
break ;
}
header_2 = obi_column_get_header_from_name ( dms_2 , (((( view_2 -> infos ) -> column_references )[ i ]). column_refs ). column_name , (((( view_2 -> infos ) -> column_references )[ i ]). column_refs ). version );
if ( header_2 == NULL )
{
obidebug ( 1 , " \n Error opening a column header while importing a view" );
return - 1 ;
}
// Update version of associated column
( header_2 -> associated_column ). version = (((( view_2 -> infos ) -> column_references )[ j ]). column_refs ). version ;
if ( obi_close_header ( header_2 ) < 0 )
{
obidebug ( 1 , " \n Error closing a column header while importing a view" );
return - 1 ;
}
}
if ( obi_close_header ( header ) < 0 )
{
obidebug ( 1 , " \n Error closing a column header while importing a view" );
return - 1 ;
}
}
2019-09-21 16:47:22 +02:00
if ( ! keep_running )
return - 1 ;
2017-08-03 16:33:12 +02:00
// Close the views
if ( obi_save_and_close_view ( view_1 ) < 0 )
{
obidebug ( 1 , " \n Error closing a view after importing from it" );
return - 1 ;
}
if ( obi_save_and_close_view ( view_2 ) < 0 )
{
obidebug ( 1 , " \n Error closing a view after importing it" );
return - 1 ;
}
// Close the DMS
2017-11-24 17:58:47 +01:00
obi_close_dms ( dms_1 , false );
obi_close_dms ( dms_2 , false );
2017-08-03 16:33:12 +02:00
return 0 ;
}
2017-10-16 10:35:07 +02:00
void obi_close_atexit ()
{
int i = 0 ;
2017-08-03 16:33:12 +02:00
2017-10-16 10:35:07 +02:00
while ( global_opened_dms_list [ i ] != NULL )
{
2017-11-24 17:58:47 +01:00
obi_close_dms ( global_opened_dms_list [ i ], true );
2017-10-16 10:35:07 +02:00
i ++ ;
}
}
2017-08-03 16:33:12 +02:00