diff options
Diffstat (limited to 'src/H5FD.c')
-rw-r--r-- | src/H5FD.c | 1642 |
1 files changed, 1642 insertions, 0 deletions
diff --git a/src/H5FD.c b/src/H5FD.c new file mode 100644 index 0000000..e8b13b7 --- /dev/null +++ b/src/H5FD.c @@ -0,0 +1,1642 @@ +/* + * Copyright © 1999 NCSA + * All rights reserved. + * + * Programmer: Robb Matzke <matzke@llnl.gov> + * Monday, July 26, 1999 + * + * Purpose: The Virtual File Layer as described in documentation. This is + * the greatest common denominator for all types of storage + * access whether a file, memory, network, etc. This layer + * usually just dispatches the request to an actual file driver + * layer. + */ + +/* Packages needed by this file */ +#include <H5private.h> /*library functions */ +#include <H5Eprivate.h> /*error handling */ +#include <H5Fprivate.h> /*files */ +#include <H5FDprivate.h> /*virtual file driver */ +#include <H5Iprivate.h> /*interface abstraction layer */ +#include <H5MMprivate.h> /*memory management */ +#include <H5Pprivate.h> /*property lists */ + +/* Interface initialization */ +#define PABLO_MASK H5FD_mask +#define INTERFACE_INIT H5FD_init_interface +static intn interface_initialize_g = 0; + +/* static prototypes */ +static herr_t H5FD_init_interface(void); +static herr_t H5FD_free_cls(H5FD_class_t *cls); + + +/*------------------------------------------------------------------------- + * Function: H5FD_init_interface + * + * Purpose: Initialize the virtual file layer. + * + * Return: Success: Non-negative + * + * Failure: Negative + * + * Programmer: Robb Matzke + * Monday, July 26, 1999 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static herr_t +H5FD_init_interface(void) +{ + FUNC_ENTER(H5FD_init_interface, FAIL); + + if (H5I_init_group(H5I_VFL, H5I_VFL_HASHSIZE, 0, + (H5I_free_t)H5FD_free_cls)<0) { + HRETURN_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, + "unable to initialize interface"); + } + + FUNC_LEAVE(SUCCEED); +} + + +/*------------------------------------------------------------------------- + * Function: H5FD_term_interface + * + * Purpose: Terminate this interface: free all memory and reset global + * variables to their initial values. Release all ID groups + * associated with this interface. + * + * Return: Success: Positive if anything was done that might + * have affected other interfaces; zero + * otherwise. + * + * Failure: Never fails. + * + * Programmer: Robb Matzke + * Friday, February 19, 1999 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +intn +H5FD_term_interface(void) +{ + intn n = 0; + + if (interface_initialize_g) { + if ((n=H5I_nmembers(H5I_VFL))) { + H5I_clear_group(H5I_VFL, FALSE); + } else { + H5I_destroy_group(H5I_VFL); + interface_initialize_g = 0; + n = 1; /*H5I*/ + } + } + return n; +} + + +/*------------------------------------------------------------------------- + * Function: H5FD_free_cls + * + * Purpose: Frees a file driver class struct and returns an indication of + * success. This function is used as the free callback for the + * virtual file layer object identifiers (cf H5FD_init_interface). + * + * Return: Success: Non-negative + * + * Failure: Negative + * + * Programmer: Robb Matzke + * Monday, July 26, 1999 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static herr_t +H5FD_free_cls(H5FD_class_t *cls) +{ + FUNC_ENTER(H5FD_free_cls, FAIL); + H5MM_xfree(cls); + FUNC_LEAVE(SUCCEED); +} + + +/*------------------------------------------------------------------------- + * Function: H5FDregister + * + * Purpose: Registers a new file driver as a member of the virtual file + * driver class. Certain fields of the class struct are + * required and that is checked here so it doesn't have to be + * checked every time the field is accessed. + * + * Return: Success: A file driver ID which is good until the + * library is closed or the driver is + * unregistered. + * + * Failure: A negative value. + * + * Programmer: Robb Matzke + * Monday, July 26, 1999 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +hid_t +H5FDregister(const H5FD_class_t *cls) +{ + hid_t retval; + H5FD_class_t *saved; + H5FD_mem_t type; + + FUNC_ENTER(H5FDregister, FAIL); + H5TRACE1("i","x",cls); + + /* Check arguments */ + if (!cls) { + HRETURN_ERROR(H5E_ARGS, H5E_UNINITIALIZED, FAIL, + "null class pointer is disallowed"); + } + if (!cls->open || !cls->close) { + HRETURN_ERROR(H5E_ARGS, H5E_UNINITIALIZED, FAIL, + "`open' and/or `close' methods are not defined"); + } + if (!cls->get_eoa || !cls->set_eoa) { + HRETURN_ERROR(H5E_ARGS, H5E_UNINITIALIZED, FAIL, + "`get_eoa' and/or `set_eoa' methods are not defined"); + } + if (!cls->get_eof) { + HRETURN_ERROR(H5E_ARGS, H5E_UNINITIALIZED, FAIL, + "`get_eof' method is not defined"); + } + if (!cls->read || !cls->write) { + HRETURN_ERROR(H5E_ARGS, H5E_UNINITIALIZED, FAIL, + "`read' and/or `write' method is not defined"); + } + for (type=0; type<H5FD_MEM_NTYPES; type++) { + if (cls->fl_map[type]<H5FD_MEM_NOLIST || + cls->fl_map[type]>=H5FD_MEM_NTYPES) { + HRETURN_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, + "invalid free-list mapping"); + } + } + + /* Copy the class structure so the caller can reuse or free it */ + if (NULL==(saved=H5MM_malloc(sizeof(H5FD_class_t)))) { + HRETURN_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, + "memory allocation failed for file driver class struct"); + } + *saved = *cls; + + /* Create the new class ID */ + if ((retval=H5I_register(H5I_VFL, saved))<0) { + HRETURN_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, + "unable to register file driver ID"); + } + + FUNC_LEAVE(retval); +} + + +/*------------------------------------------------------------------------- + * Function: H5FDunregister + * + * Purpose: Removes a driver ID from the library. This in no way affects + * file access property lists which have been defined to use + * this driver or files which are already opened under this + * driver. + * + * Return: Success: Non-negative + * + * Failure: Negative + * + * Programmer: Robb Matzke + * Monday, July 26, 1999 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5FDunregister(hid_t driver_id) +{ + FUNC_ENTER(H5FDunregister, FAIL); + H5TRACE1("e","i",driver_id); + + /* Check arguments */ + if (H5I_VFL!=H5I_get_type(driver_id) || + NULL==H5I_object(driver_id)) { + HRETURN_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, + "not a file driver"); + } + + /* The H5FD_class_t struct will be freed by this function */ + if (H5I_dec_ref(driver_id)<0) { + HRETURN_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, + "unable to unregister file driver"); + } + + FUNC_LEAVE(SUCCEED); +} + + +/*------------------------------------------------------------------------- + * Function: H5FD_fapl_copy + * + * Purpose: Copies the driver-specific part of the file access property + * list. + * + * Return: Success: Pointer to new driver-specific file access + * properties. + * + * Failure: NULL, but also returns null with no error + * pushed onto the error stack if the OLD_FAPL + * is null. + * + * Programmer: Robb Matzke + * Tuesday, August 3, 1999 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +void * +H5FD_fapl_copy(hid_t driver_id, const void *old_fapl) +{ + void *new_fapl = NULL; + H5FD_class_t *driver=NULL; + + FUNC_ENTER(H5FD_fapl_copy, NULL); + + /* Check args */ + if (H5I_VFL!=H5I_get_type(driver_id) || + NULL==(driver=H5I_object(driver_id))) { + HRETURN_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not a driver ID"); + } + if (!old_fapl) HRETURN(NULL); /*but no error*/ + + /* Allow the driver to copy or do it ourselves */ + if (driver->fapl_copy) { + new_fapl = (driver->fapl_copy)(old_fapl); + } else if (driver->fapl_size>0) { + new_fapl = H5MM_malloc(driver->fapl_size); + HDmemcpy(new_fapl, old_fapl, driver->fapl_size); + } else { + HRETURN_ERROR(H5E_VFL, H5E_UNSUPPORTED, NULL, + "no way to copy driver file access property list"); + } + + FUNC_LEAVE(new_fapl); +} + + +/*------------------------------------------------------------------------- + * Function: H5FD_fapl_free + * + * Purpose: Frees the driver-specific file access property list. + * + * Return: Success: non-negative + * + * Failure: negative + * + * Programmer: Robb Matzke + * Tuesday, August 3, 1999 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5FD_fapl_free(hid_t driver_id, void *fapl) +{ + H5FD_class_t *driver=NULL; + + FUNC_ENTER(H5FD_fapl_free, FAIL); + H5TRACE2("e","ix",driver_id,fapl); + + /* Check args */ + if (H5I_VFL!=H5I_get_type(driver_id) || + NULL==(driver=H5I_object(driver_id))) { + HRETURN_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a driver ID"); + } + + /* Allow driver to free or do it ourselves */ + if (fapl && driver->fapl_free) { + if ((driver->fapl_free)(fapl)<0) { + HRETURN_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, + "driver fapl_free request failed"); + } + } else { + H5MM_xfree(fapl); + } + + FUNC_LEAVE(SUCCEED); +} + + +/*------------------------------------------------------------------------- + * Function: H5FD_dxpl_copy + * + * Purpose: Copies the driver-specific part of the data transfer property + * list. + * + * Return: Success: Pointer to new driver-specific data transfer + * properties. + * + * Failure: NULL, but also returns null with no error + * pushed onto the error stack if the OLD_DXPL + * is null. + * + * Programmer: Robb Matzke + * Tuesday, August 3, 1999 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +void * +H5FD_dxpl_copy(hid_t driver_id, const void *old_dxpl) +{ + void *new_dxpl = NULL; + H5FD_class_t *driver=NULL; + + FUNC_ENTER(H5FD_dxpl_copy, NULL); + + /* Check args */ + if (H5I_VFL!=H5I_get_type(driver_id) || + NULL==(driver=H5I_object(driver_id))) { + HRETURN_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, + "not a driver ID"); + } + if (!old_dxpl) HRETURN(NULL); /*but no error*/ + + /* Allow the driver to copy or do it ourselves */ + if (driver->dxpl_copy) { + new_dxpl = (driver->dxpl_copy)(old_dxpl); + } else if (driver->dxpl_size>0) { + new_dxpl = H5MM_malloc(driver->dxpl_size); + HDmemcpy(new_dxpl, old_dxpl, driver->dxpl_size); + } else { + HRETURN_ERROR(H5E_VFL, H5E_UNSUPPORTED, NULL, + "no way to copy driver file access property list"); + } + + FUNC_LEAVE(new_dxpl); +} + + +/*------------------------------------------------------------------------- + * Function: H5FD_dxpl_free + * + * Purpose: Frees the driver-specific data transfer property list. + * + * Return: Success: non-negative + * + * Failure: negative + * + * Programmer: Robb Matzke + * Tuesday, August 3, 1999 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5FD_dxpl_free(hid_t driver_id, void *dxpl) +{ + H5FD_class_t *driver=NULL; + + FUNC_ENTER(H5FD_dxpl_free, FAIL); + H5TRACE2("e","ix",driver_id,dxpl); + + /* Check args */ + if (H5I_VFL!=H5I_get_type(driver_id) || + NULL==(driver=H5I_object(driver_id))) { + HRETURN_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a driver ID"); + } + + /* Allow driver to free or do it ourselves */ + if (dxpl && driver->dxpl_free) { + if ((driver->dxpl_free)(dxpl)<0) { + HRETURN_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, + "driver dxpl_free request failed"); + } + } else { + H5MM_xfree(dxpl); + } + + FUNC_LEAVE(SUCCEED); +} + + +/*------------------------------------------------------------------------- + * Function: H5FDopen + * + * Purpose: Opens a file named NAME for the type(s) of access described + * by the bit vector FLAGS according to a file access property + * list FAPL_ID (which may be the constant H5P_DEFAULT). The + * file should expect to handle format addresses in the range [0, + * MAXADDR] (if MAXADDR is the undefined address then the caller + * doesn't care about the address range). + * + * Possible values for the FLAGS bits are: + * + * H5F_ACC_RDWR: Open the file for read and write access. If + * this bit is not set then open the file for + * read only access. It is permissible to open a + * file for read and write access when only read + * access is requested by the library (the + * library will never attempt to write to a file + * which it opened with only read access). + * + * H5F_ACC_CREATE: Create the file if it doesn't already exist. + * However, see H5F_ACC_EXCL below. + * + * H5F_ACC_TRUNC: Truncate the file if it already exists. This + * is equivalent to deleting the file and then + * creating a new empty file. + * + * H5F_ACC_EXCL: When used with H5F_ACC_CREATE, if the file + * already exists then the open should fail. + * Note that this is unsupported/broken with + * some file drivers (e.g., sec2 across nfs) and + * will contain a race condition when used to + * perform file locking. + * + * The MAXADDR is the maximum address which will be requested by + * the library during an allocation operation. Usually this is + * the same value as the MAXADDR field of the class structure, + * but it can be smaller if the driver is being used under some + * other driver. + * + * Note that when the driver `open' callback gets control that + * the public part of the file struct (the H5FD_t part) will be + * incomplete and will be filled in after that callback returns. + * + * Return: Success: Pointer to a new file driver struct. + * + * Failure: NULL + * + * Programmer: Robb Matzke + * Tuesday, July 27, 1999 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +H5FD_t * +H5FDopen(const char *name, unsigned flags, hid_t fapl_id, haddr_t maxaddr) +{ + H5FD_t *ret_value=NULL; + + FUNC_ENTER(H5FDopen, NULL); + + if (NULL==(ret_value=H5FD_open(name, flags, fapl_id, maxaddr))) { + HRETURN_ERROR(H5E_VFL, H5E_CANTINIT, NULL, + "unable to open file"); + } + + FUNC_LEAVE(ret_value); +} + + +/*------------------------------------------------------------------------- + * Function: H5FD_open + * + * Purpose: Private version of H5FDopen() + * + * Return: Success: Pointer to a new file driver struct + * + * Failure: NULL + * + * Programmer: Robb Matzke + * Wednesday, August 4, 1999 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +H5FD_t * +H5FD_open(const char *name, unsigned flags, hid_t fapl_id, haddr_t maxaddr) +{ + const H5F_access_t *fapl=NULL; + H5FD_class_t *driver; + H5FD_t *file=NULL; + + FUNC_ENTER(H5FD_open, NULL); + + /* Check arguments */ + if (H5P_DEFAULT==fapl_id) { + fapl = &H5F_access_dflt; + } else if (H5P_FILE_ACCESS != H5P_get_class(fapl_id) || + NULL == (fapl = H5I_object(fapl_id))) { + HRETURN_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, + "not a file access property list"); + } + if (0==maxaddr) { + HRETURN_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, + "zero format address range"); + } + + /* Get driver info */ + if (H5I_VFL!=H5I_get_type(fapl->driver_id) || + NULL==(driver=H5I_object(fapl->driver_id))) { + HRETURN_ERROR(H5E_VFL, H5E_BADVALUE, NULL, + "invalid driver ID in file access property list"); + } + if (NULL==driver->open) { + HRETURN_ERROR(H5E_VFL, H5E_UNSUPPORTED, NULL, + "file driver has no `open' method"); + } + + /* Dispatch to file driver */ + if (HADDR_UNDEF==maxaddr) maxaddr = driver->maxaddr; + if (NULL==(file=(driver->open)(name, flags, fapl_id, maxaddr))) { + HRETURN_ERROR(H5E_VFL, H5E_CANTINIT, NULL, "open failed"); + } + + /* + * Fill in public fields. We must increment the reference count on the + * driver ID to prevent it from being freed while this file is open. + */ + file->driver_id = fapl->driver_id; + H5I_inc_ref(file->driver_id); + file->cls = driver; + file->maxaddr = maxaddr; + HDmemset(file->fl, 0, sizeof(file->fl)); + + FUNC_LEAVE(file); +} + + +/*------------------------------------------------------------------------- + * Function: H5FDclose + * + * Purpose: Closes the file by calling the driver `close' callback, which + * should free all driver-private data and free the file struct. + * Note that the public part of the file struct (the H5FD_t part) + * will be all zero during the driver close callback like during + * the `open' callback. + * + * Return: Success: Non-negative + * + * Failure: Negative + * + * Programmer: Robb Matzke + * Tuesday, July 27, 1999 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5FDclose(H5FD_t *file) +{ + FUNC_ENTER(H5FDclose, FAIL); + H5TRACE1("e","x",file); + + if (!file || !file->cls) { + HRETURN_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid file pointer"); + } + + if (H5FD_close(file)<0) { + HRETURN_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "unable to close file"); + } + + FUNC_LEAVE(SUCCEED); +} + + +/*------------------------------------------------------------------------- + * Function: H5FD_close + * + * Purpose: Private version of H5FDclose() + * + * Return: Success: Non-negative + * + * Failure: Negative + * + * Programmer: Robb Matzke + * Wednesday, August 4, 1999 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5FD_close(H5FD_t *file) +{ + const H5FD_class_t *driver; + H5FD_free_t *cur, *next; + H5FD_mem_t i; +#ifdef H5F_DEBUG + uintn nblocks=0; + hsize_t nbytes=0; +#endif + + FUNC_ENTER(H5FD_close, FAIL); + assert(file && file->cls); + + /* Free all free-lists, leaking any memory thus described */ + for (i=0; i<H5FD_MEM_NTYPES; i++) { + for (cur=file->fl[i]; cur; cur=next) { +#ifdef H5F_DEBUG + nblocks++; + nbytes += cur->size; +#endif + next = cur->next; + H5MM_xfree(cur); + } + file->fl[i]=NULL; + } +#ifdef H5F_DEBUG + if (nblocks && H5DEBUG(F)) { + fprintf(H5DEBUG(F), + "H5F: leaked %lu bytes of file memory in %u blocks\n", + (unsigned long)nbytes, nblocks); + } +#endif + + /* Prepare to close file by clearing all public fields */ + driver = file->cls; + H5I_dec_ref(file->driver_id); + HDmemset(file, 0, sizeof(H5FD_t)); + + /* + * Dispatch to the driver for actual close. If the driver fails to + * close the file then the file will be in an unusable state. + */ + assert(driver->close); + if ((driver->close)(file)<0) { + HRETURN_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "close failed"); + } + + FUNC_LEAVE(SUCCEED); +} + + +/*------------------------------------------------------------------------- + * Function: H5FDcmp + * + * Purpose: Compare the keys of two files using the file driver callback + * if the files belong to the same driver, otherwise sort the + * files by driver class pointer value. + * + * Return: Success: A value like strcmp() + * + * Failure: Must never fail. If both file handles are + * invalid then they compare equal. If one file + * handle is invalid then it compares less than + * the other. If both files belong to the same + * driver and the driver doesn't provide a + * comparison callback then the file pointers + * themselves are compared. + * + * Programmer: Robb Matzke + * Tuesday, July 27, 1999 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +int +H5FDcmp(const H5FD_t *f1, const H5FD_t *f2) +{ + intn ret_value; + + FUNC_ENTER(H5FDcmp, -1); /*return value is arbitrary*/ + H5TRACE2("Is","xx",f1,f2); + + ret_value = H5FD_cmp(f1, f2); + FUNC_LEAVE(ret_value); +} + + +/*------------------------------------------------------------------------- + * Function: H5FD_cmp + * + * Purpose: Private version of H5FDcmp() + * + * Return: Success: A value like strcmp() + * + * Failure: Must never fail. + * + * Programmer: Robb Matzke + * Wednesday, August 4, 1999 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +int +H5FD_cmp(const H5FD_t *f1, const H5FD_t *f2) +{ + intn ret_value; + + FUNC_ENTER(H5FD_cmp, -1); /*return value is arbitrary*/ + + if ((!f1 || !f1->cls) && (!f2 || !f2->cls)) return 0; + if (!f1 || !f1->cls) return -1; + if (!f2 || !f2->cls) return 1; + if (f1->cls < f2->cls) return -1; + if (f1->cls > f2->cls) return 1; + + /* Files are same driver; no cmp callback */ + if (!f1->cls->cmp) { + if (f1<f2) return -1; + if (f1>f2) return 1; + return 0; + } + + ret_value = (f1->cls->cmp)(f1, f2); + + FUNC_LEAVE(ret_value); +} + + +/*------------------------------------------------------------------------- + * Function: H5FDalloc + * + * Purpose: Allocates SIZE bytes of memory from the FILE. The memory will + * be used according to the allocation class TYPE. First we try + * to satisfy the request from one of the free lists, according + * to the free list map provided by the driver. The free list + * array has one entry for each request type and the value of + * that array element can be one of four possibilities: + * + * It can be the constant H5FD_MEM_DEFAULT (or zero) which + * indicates that the identity mapping is used. In other + * words, the request type maps to its own free list. + * + * It can be the request type itself, which has the same + * effect as the H5FD_MEM_DEFAULT value above. + * + * It can be the ID for another request type, which + * indicates that the free list for the specified type + * should be used instead. + * + * It can be the constant H5FD_MEM_NOLIST which means that + * no free list should be used for this type of request. + * + * If the request cannot be satisfied from a free list then + * either the driver's `alloc' callback is invoked (if one was + * supplied) or the end-of-address marker is extended. The + * `alloc' callback is always called with the same arguments as + * the H5FDalloc(). + * + * Return: Success: The format address of the new file memory. + * + * Failure: The undefined address HADDR_UNDEF + * + * Programmer: Robb Matzke + * Tuesday, July 27, 1999 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +haddr_t +H5FDalloc(H5FD_t *file, H5FD_mem_t type, hsize_t size) +{ + haddr_t ret_value = HADDR_UNDEF; + + FUNC_ENTER(H5FDalloc, HADDR_UNDEF); + H5TRACE3("a","xMth",file,type,size); + + /* Check args */ + if (!file || !file->cls) { + HRETURN_ERROR(H5E_ARGS, H5E_BADVALUE, HADDR_UNDEF, + "invalid file pointer"); + } + if (type<0 || type>=H5FD_MEM_NTYPES) { + HRETURN_ERROR(H5E_ARGS, H5E_BADVALUE, HADDR_UNDEF, + "invalid request type"); + } + if (size<=0) { + HRETURN_ERROR(H5E_ARGS, H5E_BADVALUE, HADDR_UNDEF, + "zero-size request"); + } + + /* Do the real work */ + if (HADDR_UNDEF==(ret_value=H5FD_alloc(file, type, size))) { + HRETURN_ERROR(H5E_VFL, H5E_CANTINIT, HADDR_UNDEF, + "unable to allocate file memory"); + } + + FUNC_LEAVE(ret_value); +} + + +/*------------------------------------------------------------------------- + * Function: H5FD_alloc + * + * Purpose: Private version of H5FDalloc() + * + * Return: Success: The format address of the new file memory. + * + * Failure: The undefined address HADDR_UNDEF + * + * Programmer: Robb Matzke + * Wednesday, August 4, 1999 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +haddr_t +H5FD_alloc(H5FD_t *file, H5FD_mem_t type, hsize_t size) +{ + haddr_t ret_value = HADDR_UNDEF; + H5FD_mem_t mapped_type; + + FUNC_ENTER(H5FD_alloc, HADDR_UNDEF); + + /* Check args */ + assert(file && file->cls); + assert(type>=0 && type<H5FD_MEM_NTYPES); + assert(size>0); + + /* Map the allocation request to a free list */ + if (H5FD_MEM_DEFAULT==file->cls->fl_map[type]) { + mapped_type = type; + } else { + mapped_type = file->cls->fl_map[type]; + } + + /* + * Try to satisfy the request from the free list. First try to find an + * exact match, otherwise use the best match. + */ + if (mapped_type>=0) { + H5FD_free_t *prev=NULL, *best=NULL; + H5FD_free_t *cur = file->fl[mapped_type]; + while (cur) { + if (cur->size==size) { + ret_value = cur->addr; + if (prev) prev->next = cur->next; + else file->fl[mapped_type] = cur->next; + H5MM_xfree(cur); + HRETURN(ret_value); + } else if (cur->size>size && + (!best || cur->size<best->size)) { + best = cur; + } + prev = cur; + cur = cur->next; + } + if (best) { + ret_value = best->addr; + best->addr += size; + best->size -= size; + HRETURN(ret_value); + } + } + + /* + * Dispatch to driver `alloc' callback or extend the end-of-address + * marker + */ + if (file->cls->alloc) { + ret_value = (file->cls->alloc)(file, type, size); + if (HADDR_UNDEF==ret_value) { + HRETURN_ERROR(H5E_VFL, H5E_NOSPACE, HADDR_UNDEF, + "driver allocation request failed"); + } + } else { + haddr_t eoa = (file->cls->get_eoa)(file); + if (H5F_addr_overflow(eoa, size) || eoa+size>file->maxaddr) { + HRETURN_ERROR(H5E_VFL, H5E_NOSPACE, HADDR_UNDEF, + "file allocation request failed"); + } + ret_value = eoa; + eoa += size; + if ((file->cls->set_eoa)(file, eoa)<0) { + HRETURN_ERROR(H5E_VFL, H5E_NOSPACE, HADDR_UNDEF, + "file allocation request failed"); + } + } + + FUNC_LEAVE(ret_value); +} + + +/*------------------------------------------------------------------------- + * Function: H5FDfree + * + * Purpose: Frees format addresses starting with ADDR and continuing for + * SIZE bytes in the file FILE. The type of space being freed is + * specified by TYPE, which is mapped to a free list as + * described for the H5FDalloc() function above. If the request + * doesn't map to a free list then either the application `free' + * callback is invoked (if defined) or the memory is leaked. + * + * Return: Success: Non-negative + * + * Failure: Negative + * + * Programmer: Robb Matzke + * Wednesday, July 28, 1999 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5FDfree(H5FD_t *file, H5FD_mem_t type, haddr_t addr, hsize_t size) +{ + FUNC_ENTER(H5FDfree, FAIL); + H5TRACE4("e","xMtah",file,type,addr,size); + + /* Check args */ + if (!file || !file->cls) { + HRETURN_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid file pointer"); + } + if (type<0 || type>=H5FD_MEM_NTYPES) { + HRETURN_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid request type"); + } + + /* Do the real work */ + if (H5FD_free(file, type, addr, size)<0) { + HRETURN_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, + "file deallocation request failed"); + } + + FUNC_LEAVE(SUCCEED); +} + + +/*------------------------------------------------------------------------- + * Function: H5FD_free + * + * Purpose: Private version of H5FDfree() + * + * Return: Success: Non-negative + * + * Failure: Negative + * + * Programmer: Robb Matzke + * Wednesday, August 4, 1999 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5FD_free(H5FD_t *file, H5FD_mem_t type, haddr_t addr, hsize_t size) +{ + H5FD_mem_t mapped_type; + + FUNC_ENTER(H5FD_free, FAIL); + + /* Check args */ + assert(file && file->cls); + assert(type>=0 && type<H5FD_MEM_NTYPES); + if (!H5F_addr_defined(addr) || addr>file->maxaddr || 0==size || + H5F_addr_overflow(addr, size) || addr+size>file->maxaddr) { + HRETURN_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid region"); + } + + /* Map request type to free list */ + if (H5FD_MEM_DEFAULT==file->cls->fl_map[type]) { + mapped_type = type; + } else { + mapped_type = file->cls->fl_map[type]; + } + + /* + * If the request maps to a free list then add memory to the free list + * without ever telling the driver that it was freed. Otherwise let the + * driver deallocate the memory. + */ + if (mapped_type>=0) { + H5FD_free_t *cur = H5MM_malloc(sizeof(H5FD_free_t)); + cur->addr = addr; + cur->size = size; + cur->next = file->fl[mapped_type]; + file->fl[mapped_type] = cur; + } else if (file->cls->free) { + if ((file->cls->free)(file, type, addr, size)<0) { + HRETURN_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, + "driver free request failed"); + } + } else { + /* leak memory */ + } + + FUNC_LEAVE(SUCCEED); +} + + +/*------------------------------------------------------------------------- + * Function: H5FDrealloc + * + * Purpose: Changes the size of an allocated chunk of memory, possibly + * also changing its location in the file. + * + * Return: Success: New address of the block of memory, not + * necessarily the same as the original address. + * + * Failure: HADDR_UNDEF + * + * Programmer: Robb Matzke + * Tuesday, August 3, 1999 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +haddr_t +H5FDrealloc(H5FD_t *file, H5FD_mem_t type, haddr_t old_addr, hsize_t old_size, + hsize_t new_size) +{ + haddr_t ret_value=HADDR_UNDEF; + + FUNC_ENTER(H5FDrealloc, HADDR_UNDEF); + H5TRACE5("a","xMtahh",file,type,old_addr,old_size,new_size); + + if (HADDR_UNDEF==(ret_value=H5FD_realloc(file, type, old_addr, old_size, + new_size))) { + HRETURN_ERROR(H5E_VFL, H5E_CANTINIT, HADDR_UNDEF, + "file reallocation request failed"); + } + + FUNC_LEAVE(ret_value); +} + + +/*------------------------------------------------------------------------- + * Function: H5FD_realloc + * + * Purpose: Private version of H5FDrealloc() + * + * Return: Success: New address of the block of memory, not + * necessarily the same as the original address. + * + * Failure: HADDR_UNDEF + * + * Programmer: Robb Matzke + * Wednesday, August 4, 1999 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +haddr_t +H5FD_realloc(H5FD_t *file, H5FD_mem_t type, haddr_t old_addr, hsize_t old_size, + hsize_t new_size) +{ + haddr_t new_addr=old_addr; + uint8_t _buf[8192]; + uint8_t *buf=_buf; + + FUNC_ENTER(H5FD_realloc, HADDR_UNDEF); + + if (new_size==old_size) { + /*nothing to do*/ + + } else if (0==old_size) { + /* allocate memory */ + assert(!H5F_addr_defined(old_addr)); + if (HADDR_UNDEF==(new_addr=H5FDalloc(file, type, new_size))) { + HRETURN_ERROR(H5E_FILE, H5E_NOSPACE, HADDR_UNDEF, + "file allocation failed"); + } + + } else if (0==new_size) { + /* free memory */ + assert(H5F_addr_defined(old_addr)); + H5FDfree(file, type, old_addr, old_size); + new_addr = HADDR_UNDEF; + + } else if (new_size<old_size) { + /* free the end of the block */ + H5FDfree(file, type, old_addr+old_size, old_size-new_size); + + } else { + /* move memory to new location */ + if (HADDR_UNDEF==(new_addr=H5FDalloc(file, type, new_size))) { + HRETURN_ERROR(H5E_FILE, H5E_NOSPACE, HADDR_UNDEF, + "file allocation failed"); + } + if (old_size>sizeof(_buf) && NULL==(buf=H5MM_malloc(old_size))) { + H5FDfree(file, type, new_addr, new_size); + HRETURN_ERROR(H5E_RESOURCE, H5E_NOSPACE, HADDR_UNDEF, + "memory allocation failed"); + } + if (H5FDread(file, H5P_DEFAULT, old_addr, old_size, buf)<0 || + H5FDwrite(file, H5P_DEFAULT, new_addr, old_size, buf)) { + H5FDfree(file, type, new_addr, new_size); + H5MM_xfree(buf); + HRETURN_ERROR(H5E_FILE, H5E_READERROR, HADDR_UNDEF, + "unable to move file block"); + } + + if (buf!=_buf) H5MM_xfree(buf); + H5FDfree(file, type, old_addr, old_size); + } + + FUNC_LEAVE(new_addr); +} + + +/*------------------------------------------------------------------------- + * Function: H5FDget_eoa + * + * Purpose: Returns the address of the first byte after the last + * allocated memory in the file. + * + * Return: Success: First byte after allocated memory. + * + * Failure: HADDR_UNDEF + * + * Programmer: Robb Matzke + * Friday, July 30, 1999 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +haddr_t +H5FDget_eoa(H5FD_t *file) +{ + haddr_t addr; + + FUNC_ENTER(H5FDget_eoa, HADDR_UNDEF); + H5TRACE1("a","x",file); + + /* Check args */ + if (!file || !file->cls) { + HRETURN_ERROR(H5E_ARGS, H5E_BADVALUE, HADDR_UNDEF, + "invalid file pointer"); + } + + /* The real work */ + if (HADDR_UNDEF==(addr=H5FD_get_eoa(file))) { + HRETURN_ERROR(H5E_VFL, H5E_CANTINIT, HADDR_UNDEF, + "file get eoa request failed"); + } + + FUNC_LEAVE(addr); +} + + +/*------------------------------------------------------------------------- + * Function: H5FD_get_eoa + * + * Purpose: Private version of H5FDget_eoa() + * + * Return: Success: First byte after allocated memory. + * + * Failure: HADDR_UNDEF + * + * Programmer: Robb Matzke + * Wednesday, August 4, 1999 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +haddr_t +H5FD_get_eoa(H5FD_t *file) +{ + haddr_t addr; + + FUNC_ENTER(H5FD_get_eoa, HADDR_UNDEF); + assert(file && file->cls); + + /* Dispatch to driver */ + if (HADDR_UNDEF==(addr=(file->cls->get_eoa)(file))) { + HRETURN_ERROR(H5E_VFL, H5E_CANTINIT, HADDR_UNDEF, + "driver get_eoa request failed"); + } + + FUNC_LEAVE(addr); +} + + +/*------------------------------------------------------------------------- + * Function: H5FDset_eoa + * + * Purpose: Set the end-of-address marker for the file. The ADDR is the + * address of the first byte past the last allocated byte of the + * file. This function is called from two places: + * + * It is called after an existing file is opened in order to + * "allocate" enough space to read the superblock and then + * to "allocate" the entire hdf5 file based on the contents + * of the superblock. + * + * It is called during file memory allocation if the + * allocation request cannot be satisfied from the free list + * and the driver didn't supply an allocation callback. + * + * Return: Success: Non-negative + * + * Failure: Negative, no side effect + * + * Programmer: Robb Matzke + * Friday, July 30, 1999 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5FDset_eoa(H5FD_t *file, haddr_t addr) +{ + FUNC_ENTER(H5FDset_eoa, FAIL); + H5TRACE2("e","xa",file,addr); + + /* Check args */ + if (!file || !file->cls) { + HRETURN_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid file pointer"); + } + if (!H5F_addr_defined(addr) || addr>file->maxaddr) { + HRETURN_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, + "invalid end-of-address value"); + } + + /* The real work */ + if (H5FD_set_eoa(file, addr)<0) { + HRETURN_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, + "file set eoa request failed"); + } + + FUNC_LEAVE(SUCCEED); +} + + +/*------------------------------------------------------------------------- + * Function: H5FD_set_eoa + * + * Purpose: Private version of H5FDset_eoa() + * + * Return: Success: Non-negative + * + * Failure: Negative, no side effect + * + * Programmer: Robb Matzke + * Wednesday, August 4, 1999 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5FD_set_eoa(H5FD_t *file, haddr_t addr) +{ + FUNC_ENTER(H5FD_set_eoa, FAIL); + assert(file && file->cls); + assert(H5F_addr_defined(addr) && addr<=file->maxaddr); + + /* Dispatch to driver */ + if ((file->cls->set_eoa)(file, addr)<0) { + HRETURN_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, + "driver set_eoa request failed"); + } + + FUNC_LEAVE(SUCCEED); +} + + +/*------------------------------------------------------------------------- + * Function: H5FDget_eof + * + * Purpose: Returns the end-of-file address, which is the greater of the + * end-of-format address and the actual EOF marker. This + * function is called after an existing file is opened in order + * for the library to learn the true size of the underlying file + * and to determine whether the hdf5 data has been truncated. + * + * It is also used when a file is first opened to learn whether + * the file is empty or not. + * + * It is permissible for the driver to return the maximum address + * for the file size if the file is not empty. + * + * Return: Success: The EOF address. + * + * Failure: HADDR_UNDEF + * + * Programmer: Robb Matzke + * Thursday, July 29, 1999 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +haddr_t +H5FDget_eof(H5FD_t *file) +{ + haddr_t addr; + + FUNC_ENTER(H5FDget_eof, HADDR_UNDEF); + H5TRACE1("a","x",file); + + /* Check arguments */ + if (!file || !file->cls) { + HRETURN_ERROR(H5E_ARGS, H5E_BADVALUE, HADDR_UNDEF, + "invalid file pointer"); + } + + /* The real work */ + if (HADDR_UNDEF==(addr=H5FD_get_eof(file))) { + HRETURN_ERROR(H5E_VFL, H5E_CANTINIT, HADDR_UNDEF, + "file get eof request failed"); + } + + FUNC_LEAVE(addr); +} + + +/*------------------------------------------------------------------------- + * Function: H5FD_get_eof + * + * Purpose: Private version of H5FDget_eof() + * + * Return: Success: The EOF address. + * + * Failure: HADDR_UNDEF + * + * Programmer: Robb Matzke + * Wednesday, August 4, 1999 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +haddr_t +H5FD_get_eof(H5FD_t *file) +{ + haddr_t addr=HADDR_UNDEF; + + FUNC_ENTER(H5FD_get_eof, HADDR_UNDEF); + assert(file && file->cls); + + /* Dispatch to driver */ + if (file->cls->get_eof) { + if (HADDR_UNDEF==(addr=(file->cls->get_eof)(file))) { + HRETURN_ERROR(H5E_VFL, H5E_CANTINIT, HADDR_UNDEF, + "driver get_eof request failed"); + } + } else { + addr = file->maxaddr; + } + + FUNC_LEAVE(addr); +} + + +/*------------------------------------------------------------------------- + * Function: H5FDread + * + * Purpose: Reads SIZE bytes from FILE beginning at address ADDR + * according to the data transfer property list DXPL_ID (which may + * be the constant H5P_DEFAULT). The result is written into the + * buffer BUF. + * + * Return: Success: Non-negative. The read result is written into + * the BUF buffer which should be allocated by + * the caller. + * + * Failure: Negative. The contents of BUF is undefined. + * + * Programmer: Robb Matzke + * Thursday, July 29, 1999 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5FDread(H5FD_t *file, hid_t dxpl_id, haddr_t addr, hsize_t size, + void *buf/*out*/) +{ + FUNC_ENTER(H5FDread, FAIL); + H5TRACE5("e","xiahx",file,dxpl_id,addr,size,buf); + + /* Check args */ + if (!file || !file->cls) { + HRETURN_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid file pointer"); + } + if (H5P_DEFAULT!=dxpl_id && + (H5P_DATA_XFER!=H5P_get_class(dxpl_id) || + NULL==H5I_object(dxpl_id))) { + HRETURN_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, + "not a data transfer property list"); + } + if (!buf) { + HRETURN_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "null result buffer"); + } + + /* Do the real work */ + if (H5FD_read(file, dxpl_id, addr, size, buf)<0) { + HRETURN_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "file read request failed"); + } + + FUNC_LEAVE(SUCCEED); +} + + +/*------------------------------------------------------------------------- + * Function: H5FD_read + * + * Purpose: Private version of H5FDread() + * + * Return: Success: Non-negative + * + * Failure: Negative + * + * Programmer: Robb Matzke + * Wednesday, August 4, 1999 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5FD_read(H5FD_t *file, hid_t dxpl_id, haddr_t addr, hsize_t size, + void *buf/*out*/) +{ + FUNC_ENTER(H5FD_read, FAIL); + assert(file && file->cls); + assert(H5P_DEFAULT==dxpl_id || + (H5P_DATA_XFER==H5P_get_class(dxpl_id) || H5I_object(dxpl_id))); + assert(buf); + + /* The no-op case */ + if (0==size) HRETURN(SUCCEED); + + /* Dispatch to driver */ + if ((file->cls->read)(file, dxpl_id, addr, size, buf)<0) { + HRETURN_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, + "driver read request failed"); + } + + FUNC_LEAVE(SUCCEED); +} + + +/*------------------------------------------------------------------------- + * Function: H5FDwrite + * + * Purpose: Writes SIZE bytes to FILE beginning at address ADDR according + * to the data transfer property list DXPL_ID (which may be the + * constant H5P_DEFAULT). The bytes to be written come from the + * buffer BUF. + * + * Return: Success: Non-negative + * + * Failure: Negative + * + * Programmer: Robb Matzke + * Thursday, July 29, 1999 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5FDwrite(H5FD_t *file, hid_t dxpl_id, haddr_t addr, hsize_t size, + const void *buf) +{ + FUNC_ENTER(H5FDwrite, FAIL); + H5TRACE5("e","xiahx",file,dxpl_id,addr,size,buf); + + /* Check args */ + if (!file || !file->cls) { + HRETURN_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid file pointer"); + } + if (H5P_DEFAULT!=dxpl_id && + (H5P_DATA_XFER!=H5P_get_class(dxpl_id) || + NULL==H5I_object(dxpl_id))) { + HRETURN_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, + "not a data transfer property list"); + } + if (!buf) { + HRETURN_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "null buffer"); + } + + /* The real work */ + if (H5FD_write(file, dxpl_id, addr, size, buf)<0) { + HRETURN_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, + "file write request failed"); + } + + FUNC_LEAVE(SUCCEED); +} + + +/*------------------------------------------------------------------------- + * Function: H5FD_write + * + * Purpose: Private version of H5FDwrite() + * + * Return: Success: Non-negative + * + * Failure: Negative + * + * Programmer: Robb Matzke + * Wednesday, August 4, 1999 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5FD_write(H5FD_t *file, hid_t dxpl_id, haddr_t addr, hsize_t size, + const void *buf) +{ + FUNC_ENTER(H5FD_write, FAIL); + assert(file && file->cls); + assert(H5P_DEFAULT==dxpl_id || + (H5P_DATA_XFER==H5P_get_class(dxpl_id) && H5I_object(dxpl_id))); + assert(buf); + + /* The no-op case */ + if (0==size) HRETURN(SUCCEED); + + /* Dispatch to driver */ + if ((file->cls->write)(file, dxpl_id, addr, size, buf)<0) { + HRETURN_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, + "driver write request failed"); + } + + FUNC_LEAVE(SUCCEED); +} + + +/*------------------------------------------------------------------------- + * Function: H5FDflush + * + * Purpose: Notify driver to flush all cached data. If the driver has no + * flush method then nothing happens. + * + * Return: Success: Non-negative + * + * Failure: Negative + * + * Programmer: Robb Matzke + * Thursday, July 29, 1999 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5FDflush(H5FD_t *file) +{ + FUNC_ENTER(H5FDflush, FAIL); + H5TRACE1("e","x",file); + + /* Check args */ + if (!file || !file->cls) { + HRETURN_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid file pointer"); + } + + /* Do the real work */ + if (H5FD_flush(file)<0) { + HRETURN_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, + "file flush request failed"); + } + + FUNC_LEAVE(SUCCEED); +} + + +/*------------------------------------------------------------------------- + * Function: H5FD_flush + * + * Purpose: Private version of H5FDflush() + * + * Return: Success: Non-negative + * + * Failure: Negative + * + * Programmer: Robb Matzke + * Wednesday, August 4, 1999 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5FD_flush(H5FD_t *file) +{ + FUNC_ENTER(H5FD_flush, FAIL); + assert(file && file->cls); + + if (file->cls->flush && + (file->cls->flush)(file)<0) { + HRETURN_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, + "driver flush request failed"); + } + + FUNC_LEAVE(SUCCEED); +} |