/* * Copyright © 1999 NCSA * All rights reserved. * * Programmer: Robb Matzke * 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. */ #define H5F_PACKAGE /*suppress error about including H5Fpkg */ /* Packages needed by this file */ #include /*library functions */ #include /*error handling */ #include /*files */ #include /*virtual file driver */ #include /*Free Lists */ #include /*interface abstraction layer */ #include /*memory management */ #include /*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); static haddr_t H5FD_real_alloc(H5FD_t *file, H5FD_mem_t type, hsize_t size); /* Declare a PQ free list to manage the metadata accumulator buffer */ H5FL_BLK_DEFINE_STATIC(meta_accum); /*------------------------------------------------------------------------- * 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=H5FD_MEM_DEFAULT; typefl_map[type]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) { H5MM_xfree(saved); 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_get_class * * Purpose: Optains a pointer to the driver struct containing all the * callback pointers, etc. The PLIST_ID argument can be a file * access property list, a data transfer property list, or a * file driver identifier. * * Return: Success: Ptr to the driver information. The pointer is * only valid as long as the driver remains * registered or some file or property list * exists which references the driver. * * Failure: NULL * * Programmer: Robb Matzke * Friday, August 20, 1999 * * Modifications: * *------------------------------------------------------------------------- */ H5FD_class_t * H5FD_get_class(hid_t id) { H5FD_class_t *ret_value=NULL; H5F_access_t *fapl=NULL; H5D_xfer_t *dxpl=NULL; FUNC_ENTER(H5FD_get_class, NULL); if (H5P_DEFAULT==id) { ret_value = H5FD_get_class(H5F_access_dflt.driver_id); } else if (H5I_VFL==H5I_get_type(id)) { ret_value = H5I_object(id); } else { switch (H5P_get_class(id)) { case H5P_FILE_ACCESS: if (NULL==(fapl=H5I_object(id))) { HRETURN_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not a file access property list"); } ret_value = H5FD_get_class(fapl->driver_id); break; case H5P_DATA_XFER: if (NULL==(dxpl=H5I_object(id))) { HRETURN_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not a data transfer property list"); } ret_value = H5FD_get_class(dxpl->driver_id); break; default: HRETURN_ERROR(H5E_ARGS, H5E_BADTYPE, NULL, "not a driver id, file access property list or " "data transfer property list"); } } FUNC_LEAVE(ret_value); } /*------------------------------------------------------------------------- * Function: H5FD_sb_size * * Purpose: Obtains the number of bytes required to store the driver file * access data in the HDF5 superblock. * * Return: Success: Number of bytes required. * * Failure: 0 if an error occurs or if the driver has no * data to store in the superblock. * * Programmer: Robb Matzke * Monday, August 16, 1999 * * Modifications: * *------------------------------------------------------------------------- */ hsize_t H5FD_sb_size(H5FD_t *file) { hsize_t ret_value=0; FUNC_ENTER(H5FD_sb_size, 0); assert(file && file->cls); if (file->cls->sb_size) { ret_value = (file->cls->sb_size)(file); } FUNC_LEAVE(ret_value); } /*------------------------------------------------------------------------- * Function: H5FD_sb_encode * * Purpose: Encode driver-specific data into the output arguments. The * NAME is a nine-byte buffer which should get an * eight-character driver name and/or version followed by a null * terminator. The BUF argument is a buffer to receive the * encoded driver-specific data. The size of the BUF array is * the size returned by the H5FD_sb_size() call. * * Return: Success: Non-negative * * Failure: Negative * * Programmer: Robb Matzke * Monday, August 16, 1999 * * Modifications: * *------------------------------------------------------------------------- */ herr_t H5FD_sb_encode(H5FD_t *file, char *name/*out*/, uint8_t *buf) { FUNC_ENTER(H5FD_sb_encode, FAIL); assert(file && file->cls); if (file->cls->sb_encode && (file->cls->sb_encode)(file, name/*out*/, buf/*out*/)<0) { HRETURN_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "driver sb_encode request failed"); } FUNC_LEAVE(SUCCEED); } /*------------------------------------------------------------------------- * Function: H5FD_sb_decode * * Purpose: Decodes the driver information block. * * Return: Success: Non-negative * * Failure: Negative * * Programmer: Robb Matzke * Monday, August 16, 1999 * * Modifications: * *------------------------------------------------------------------------- */ herr_t H5FD_sb_decode(H5FD_t *file, const char *name, const uint8_t *buf) { FUNC_ENTER(H5FD_sb_decode, FAIL); assert(file && file->cls); if (file->cls->sb_decode && (file->cls->sb_decode)(file, name, buf)<0) { HRETURN_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "driver sb_decode request failed"); } FUNC_LEAVE(SUCCEED); } /*------------------------------------------------------------------------- * Function: H5FD_fapl_get * * Purpose: Gets the file access property list associated with a file. * Usually the file will copy what it needs from the original * file access property list when the file is created. The * purpose of this function is to create a new file access * property list based on the settings in the file, which may * have been modified from the original file access property * list. * * Return: Success: Pointer to a new file access property list * with all members copied. If the file is * closed then this property list lives on, and * vice versa. * * Failure: NULL, including when the file has no * properties. * * Programmer: Robb Matzke * Friday, August 13, 1999 * * Modifications: * *------------------------------------------------------------------------- */ void * H5FD_fapl_get(H5FD_t *file) { void *ret_value=NULL; FUNC_ENTER(H5FD_fapl_get, NULL); assert(file); if (file->cls->fapl_get) { ret_value = (file->cls->fapl_get)(file); } FUNC_LEAVE(ret_value); } /*------------------------------------------------------------------------- * 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)); file->def_meta_block_size = fapl->meta_block_size; file->accum_loc = HADDR_UNDEF; /* Retrieve the VFL driver feature flags */ if (H5FD_query(file, &(file->feature_flags))<0) HRETURN_ERROR(H5E_VFL, H5E_CANTINIT, NULL, "unable to query file driver"); 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 */ /* Also leaks file space allocated but not used when metadata aggregation is turned on */ for (i=H5FD_MEM_DEFAULT; ifl[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 /* Check if we need to reset the metadata accumulator information */ if(file->feature_flags&H5FD_FEAT_ACCUMULATE_METADATA) { /* Free the buffer */ if(file->meta_accum!=NULL) file->meta_accum=H5FL_BLK_FREE(meta_accum,file->meta_accum); /* Reset the buffer sizes & location */ file->accum_buf_size=file->accum_size=0; file->accum_loc=HADDR_UNDEF; file->accum_dirty=0; } /* end if */ /* 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 (f1f2) return 1; return 0; } ret_value = (f1->cls->cmp)(f1, f2); FUNC_LEAVE(ret_value); } /*------------------------------------------------------------------------- * Function: H5FDquery * * Purpose: Query a VFL driver for its feature flags. (listed in H5FDpublic.h) * * Return: Success: non-negative * * Failure: negative * * Programmer: Quincey Koziol * Friday, August 25, 2000 * * Modifications: * *------------------------------------------------------------------------- */ int H5FDquery(const H5FD_t *f, unsigned long *flags) { intn ret_value; FUNC_ENTER(H5FDquery, FAIL); assert(f); assert(flags); ret_value = H5FD_query(f, flags); FUNC_LEAVE(ret_value); } /* end H5FDquery() */ /*------------------------------------------------------------------------- * Function: H5FD_query * * Purpose: Private version of H5FDquery() * * Return: Success: non-negative * * Failure: negative * * Programmer: Quincey Koziol * Friday, August 25, 2000 * * Modifications: * *------------------------------------------------------------------------- */ int H5FD_query(const H5FD_t *f, unsigned long *flags) { intn ret_value=0; FUNC_ENTER(H5FD_query, FAIL); assert(f); assert(flags); /* Check for query driver and call it */ if (f->cls->query) ret_value = (f->cls->query)(f, flags); else *flags=0; FUNC_LEAVE(ret_value); } /* end H5FD_query() */ /*------------------------------------------------------------------------- * 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 && type0); /* 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. Only perform the search if * the free list has the potential of satisfying the request. */ if (mapped_type>=0 && (0==file->maxsize || size<=file->maxsize)) { H5FD_free_t *prev=NULL, *best=NULL; H5FD_free_t *cur = file->fl[mapped_type]; while (cur) { file->maxsize = MAX(file->maxsize, cur->size); if (cur->size==size) { ret_value = cur->addr; if (prev) prev->next = cur->next; else file->fl[mapped_type] = cur->next; H5MM_xfree(cur); if (size==file->maxsize) file->maxsize=0; /*unknown*/ HRETURN(ret_value); } else if (cur->size>size && (!best || cur->sizesize)) { best = cur; } prev = cur; cur = cur->next; } if (best) { if (best->size==file->maxsize) file->maxsize=0; /*unknown*/ ret_value = best->addr; best->addr += size; best->size -= size; HRETURN(ret_value); } } /* * If the metadata aggregation feature is enabled for this VFL driver, * allocate "generic" metadata space and sub-allocate out of that, if * possible. Otherwise just allocate through H5FD_real_alloc() */ /* Allocate all types of metadata out of the metadata block */ if((file->feature_flags&H5FD_FEAT_AGGREGATE_METADATA) && type!=H5FD_MEM_DRAW) { /* Check if the space requested is larger than the space left in the block */ if(size>file->cur_meta_block_size) { /* Check if the block asked for is too large for a metadata block */ if(size>=file->def_meta_block_size) { /* Allocate just enough room for this new block the regular way */ ret_value=H5FD_real_alloc(file,type,size); } /* end if */ else { /* * Instead of just dropping the remainder of the block on the * floor and leaving the space in the file unused, we should * return this small piece of unused space to the free list * management. - QAK */ /* Allocate another metadata block */ file->eoma=H5FD_real_alloc(file,H5FD_MEM_DEFAULT,file->def_meta_block_size); file->cur_meta_block_size=file->def_meta_block_size; /* Allocate space out of the metadata block */ ret_value=file->eoma; file->cur_meta_block_size-=size; file->eoma+=size; } /* end else */ } /* end if */ else { /* Allocate space out of the metadata block */ ret_value=file->eoma; file->cur_meta_block_size-=size; file->eoma+=size; } /* end else */ } /* end if */ else { /* Allocate data the regular way */ ret_value=H5FD_real_alloc(file,type,size); } /* end else */ FUNC_LEAVE(ret_value); } /*------------------------------------------------------------------------- * Function: H5FD_real_alloc * * Purpose: Double private version of H5FDalloc() :-) * * Return: Success: The format address of the new file memory. * * Failure: The undefined address HADDR_UNDEF * * Programmer: Quincey Koziol * Friday, August 25, 2000 * * Modifications: * *------------------------------------------------------------------------- */ static haddr_t H5FD_real_alloc(H5FD_t *file, H5FD_mem_t type, hsize_t size) { haddr_t ret_value = HADDR_UNDEF; FUNC_ENTER(H5FD_real_alloc, HADDR_UNDEF); /* Check args */ assert(file && file->cls); assert(type>=0 && type0); /* * 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); } /* end H5FD_real_alloc() */ /*------------------------------------------------------------------------- * 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 && typefile->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; if (file->maxsize && size>file->maxsize) { file->maxsize = size; } } 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_sizesizeof(_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, type, H5P_DEFAULT, old_addr, old_size, buf)<0 || H5FDwrite(file, type, 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, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, hsize_t size, void *buf/*out*/) { FUNC_ENTER(H5FDread, FAIL); H5TRACE6("e","xMtiahx",file,type,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, type, 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, H5FD_mem_t type, 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); /* Check if this information is in the metadata accumulator */ if((file->feature_flags&H5FD_FEAT_ACCUMULATE_METADATA) && ((addr>=file->accum_loc && addr <=(file->accum_loc+file->accum_size)) || ((addr+size)>=file->accum_loc && (addr+size)<=(file->accum_loc+file->accum_size)) || (addraccum_loc && (addr+size)>(file->accum_loc+file->accum_size)))) { unsigned char *read_buf=(unsigned char *)buf; /* Pointer to the buffer being read in */ hsize_t amount_read; /* Amount to read at a time */ hsize_t read_off; /* Offset to read from */ /* Double check that we aren't reading raw data */ assert(type!=H5FD_MEM_DRAW); /* Read the part before the metadata accumulator */ if(addraccum_loc) { /* Set the amount to read */ amount_read=file->accum_loc-addr; /* Dispatch to driver */ if ((file->cls->read)(file, type, dxpl_id, addr, amount_read, read_buf)<0) HRETURN_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "driver read request failed"); /* Adjust the buffer, address & size */ read_buf+=amount_read; addr+=amount_read; size-=amount_read; } /* end if */ /* Read the part overlapping the metadata accumulator */ if(size>0 && (addr>=file->accum_loc && addr<(file->accum_loc+file->accum_size))) { /* Set the offset to "read" from */ read_off=addr-file->accum_loc; /* Set the amount to "read" */ amount_read=MIN((file->accum_size-read_off),size); /* Copy the data out of the buffer */ HDmemcpy(read_buf,file->meta_accum+read_off,amount_read); /* Adjust the buffer, address & size */ read_buf+=amount_read; addr+=amount_read; size-=amount_read; } /* end if */ /* Read the part after the metadata accumulator */ if(size>0 && addr>=(file->accum_loc+file->accum_size)) { /* Dispatch to driver */ if ((file->cls->read)(file, type, dxpl_id, addr, size, read_buf)<0) HRETURN_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "driver read request failed"); /* Adjust the buffer, address & size */ read_buf+=size; addr+=size; size-=size; } /* end if */ /* Make certain we've read it all */ assert(size==0); } /* end if */ else { /* Dispatch to driver */ if ((file->cls->read)(file, type, dxpl_id, addr, size, buf)<0) HRETURN_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "driver read request failed"); } /* end else */ 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, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, hsize_t size, const void *buf) { FUNC_ENTER(H5FDwrite, FAIL); H5TRACE6("e","xMtiahx",file,type,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, type, 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, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, hsize_t size, const void *buf) { size_t new_size; /* New size of the accumulator buffer */ size_t old_offset; /* Offset of old data within the accumulator buffer */ 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); /* Check for accumulating metadata */ if((file->feature_flags&H5FD_FEAT_ACCUMULATE_METADATA) && type!=H5FD_MEM_DRAW) { /* Check if there is already metadata in the accumulator */ if(file->accum_size>0) { /* Check if the piece of metadata being written adjoins or is inside the metadata accumulator */ if((addr>=file->accum_loc && addr <=(file->accum_loc+file->accum_size)) || ((addr+size)>=file->accum_loc && (addr+size)<=(file->accum_loc+file->accum_size)) || (addraccum_loc && (addr+size)>(file->accum_loc+file->accum_size))) { /* Check if the new metadata adjoins the beginning of the current accumulator */ if((addr+size)==file->accum_loc) { /* Check if we need more buffer space */ if((size+file->accum_size)>file->accum_buf_size) { /* Reallocate the metadata accumulator buffer */ if ((file->meta_accum=H5FL_BLK_REALLOC(meta_accum,file->meta_accum,size+file->accum_size))==NULL) HRETURN_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate metadata accumulator buffer"); /* Note the new buffer size */ file->accum_buf_size=size+file->accum_size; } /* end if */ /* Move the existing metadata to the proper location */ HDmemmove(file->meta_accum+size,file->meta_accum,file->accum_size); /* Copy the new metadata at the front */ HDmemcpy(file->meta_accum,buf,size); /* Set the new size & location of the metadata accumulator */ file->accum_loc=addr; file->accum_size=file->accum_size+size; /* Mark it as written to */ file->accum_dirty=TRUE; } /* end if */ /* Check if the new metadata adjoins the end of the current accumulator */ else if(addr==(file->accum_loc+file->accum_size)) { /* Check if we need more buffer space */ if((size+file->accum_size)>file->accum_buf_size) { /* Reallocate the metadata accumulator buffer */ if ((file->meta_accum=H5FL_BLK_REALLOC(meta_accum,file->meta_accum,size+file->accum_size))==NULL) HRETURN_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate metadata accumulator buffer"); /* Note the new buffer size */ file->accum_buf_size=size+file->accum_size; } /* end if */ /* Copy the new metadata to the end */ HDmemcpy(file->meta_accum+file->accum_size,buf,size); /* Set the new size of the metadata accumulator */ file->accum_size=file->accum_size+size; /* Mark it as written to */ file->accum_dirty=TRUE; } /* end if */ /* Check if the new metadata is entirely within the current accumulator */ else if(addr>=file->accum_loc && (addr+size)<=(file->accum_loc+file->accum_size)) { /* Copy the new metadata to the proper location within the accumulator */ HDmemcpy(file->meta_accum+(addr-file->accum_loc),buf,size); /* Mark it as written to */ file->accum_dirty=TRUE; } /* end if */ /* Check if the new metadata overlaps the beginning of the current accumulator */ else if(addraccum_loc && (addr+size)<=(file->accum_loc+file->accum_size)) { /* Calculate the new accumulator size, based on the amount of overlap */ new_size=(file->accum_loc-addr)+file->accum_size; /* Check if we need more buffer space */ if(new_size>file->accum_buf_size) { /* Reallocate the metadata accumulator buffer */ if ((file->meta_accum=H5FL_BLK_REALLOC(meta_accum,file->meta_accum,new_size))==NULL) HRETURN_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate metadata accumulator buffer"); /* Note the new buffer size */ file->accum_buf_size=new_size; } /* end if */ /* Calculate the proper offset of the existing metadata */ old_offset=(addr+size)-file->accum_loc; /* Move the existing metadata to the proper location */ HDmemmove(file->meta_accum+size,file->meta_accum+old_offset,file->accum_size-old_offset); /* Copy the new metadata at the front */ HDmemcpy(file->meta_accum,buf,size); /* Set the new size & location of the metadata accumulator */ file->accum_loc=addr; file->accum_size=new_size; /* Mark it as written to */ file->accum_dirty=TRUE; } /* end if */ /* Check if the new metadata overlaps the end of the current accumulator */ else if(addr>=file->accum_loc && (addr+size)>(file->accum_loc+file->accum_size)) { /* Calculate the new accumulator size, based on the amount of overlap */ new_size=file->accum_size+((addr+size)-(file->accum_loc+file->accum_size)); /* Check if we need more buffer space */ if(new_size>file->accum_buf_size) { /* Reallocate the metadata accumulator buffer */ if ((file->meta_accum=H5FL_BLK_REALLOC(meta_accum,file->meta_accum,new_size))==NULL) HRETURN_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate metadata accumulator buffer"); /* Note the new buffer size */ file->accum_buf_size=new_size; } /* end if */ /* Copy the new metadata to the end */ HDmemcpy(file->meta_accum+(addr-file->accum_loc),buf,size); /* Set the new size & location of the metadata accumulator */ file->accum_loc=addr; file->accum_size=new_size; /* Mark it as written to */ file->accum_dirty=TRUE; } /* end if */ else { assert(0 && "New metadata overlapped both beginning and end of existing metadata accumulator!"); } /* end else */ } /* end if */ /* New piece of metadata doesn't adjoin or overlap the existing accumulator */ else { /* Write out the existing metadata accumulator, with dispatch to driver */ if ((file->cls->write)(file, type, dxpl_id, file->accum_loc, file->accum_size, file->meta_accum)<0) HRETURN_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "driver write request failed"); /* Cache the new piece of metadata */ /* Check if we need to reallocate the buffer */ if(size>file->accum_buf_size) { /* Reallocate the metadata accumulator buffer */ if ((file->meta_accum=H5FL_BLK_REALLOC(meta_accum,file->meta_accum,size))==NULL) HRETURN_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate metadata accumulator buffer"); /* Note the new buffer size */ file->accum_buf_size=size; } /* end if */ /* Store the piece of metadata in the accumulator */ file->accum_loc=addr; file->accum_size=size; file->accum_dirty=TRUE; HDmemcpy(file->meta_accum,buf,size); } /* end else */ } /* end if */ /* No metadata in the accumulator, grab this piece and keep it */ else { /* Check if we need to reallocate the buffer */ if(size>file->accum_buf_size) { /* Reallocate the metadata accumulator buffer */ if ((file->meta_accum=H5FL_BLK_REALLOC(meta_accum,file->meta_accum,size))==NULL) HRETURN_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate metadata accumulator buffer"); /* Note the new buffer size */ file->accum_buf_size=size; } /* end if */ /* Store the piece of metadata in the accumulator */ file->accum_loc=addr; file->accum_size=size; file->accum_dirty=TRUE; HDmemcpy(file->meta_accum,buf,size); } /* end else */ } /* end if */ else { /* Dispatch to driver */ if ((file->cls->write)(file, type, dxpl_id, addr, size, buf)<0) HRETURN_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "driver write request failed"); } /* end else */ 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); /* Check if we need to flush out the metadata accumulator */ if((file->feature_flags&H5FD_FEAT_ACCUMULATE_METADATA) && file->accum_dirty && file->accum_size>0) { /* Flush the metadata contents */ /* Not certain if the type and dxpl should be the way they are... -QAK */ if ((file->cls->write)(file, H5FD_MEM_DEFAULT, H5P_DEFAULT, file->accum_loc, file->accum_size, file->meta_accum)<0) HRETURN_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "driver write request failed"); /* Reset the dirty flag */ file->accum_dirty=FALSE; } /* end if */ if (file->cls->flush && (file->cls->flush)(file)<0) HRETURN_ERROR(H5E_VFL, H5E_CANTINIT, FAIL, "driver flush request failed"); FUNC_LEAVE(SUCCEED); }