/* * Copyright (C) 1997 NCSA * All rights reserved. * * Programmer: Robb Matzke * Wednesday, October 22, 1997 * * Purpose: This file contains virtual functions for the H5F_low * class. These are functions that operate on various kinds * of files at a level where the file is just a one-dimensional * array of bytes. */ #include #include #include #include #define PABLO_MASK H5Flow_mask static intn interface_initialize_g = 0; #define INTERFACE_INIT NULL /*------------------------------------------------------------------------- * Function: H5F_low_class * * Purpose: Given a driver identifier return the class pointer for that * low-level driver. * * Return: Success: A low-level driver class pointer. * * Failure: NULL * * Programmer: Robb Matzke * Wednesday, February 18, 1998 * * Modifications: * *------------------------------------------------------------------------- */ const H5F_low_class_t * H5F_low_class (H5F_driver_t driver) { const H5F_low_class_t *type = NULL; FUNC_ENTER (H5F_low_class, NULL); switch (driver) { case H5F_LOW_STDIO: type = H5F_LOW_STDIO_g; break; case H5F_LOW_SEC2: type = H5F_LOW_SEC2_g; break; case H5F_LOW_CORE: type = H5F_LOW_CORE_g; break; #ifdef HAVE_PARALLEL case H5F_LOW_MPIO: type = H5F_LOW_MPIO_g; break; #endif case H5F_LOW_SPLIT: type = H5F_LOW_SPLIT_g; break; case H5F_LOW_FAMILY: type = H5F_LOW_FAMILY_g; break; default: HRETURN_ERROR (H5E_IO, H5E_UNSUPPORTED, NULL, "unknown low-level driver"); } FUNC_LEAVE (type); } /*------------------------------------------------------------------------- * Function: H5F_low_open * * Purpose: Opens a file of type TYPE with name NAME according to the * field of bit flags FLAGS which are: * * H5F_ACC_WRITE: The file is open for read/write access. * Without this bit set, the file would be open * for read-only access. * * H5F_ACC_CREAT: The file is created if it doesn't already * exist. On unix, the file permissions are set * to 0666 modified by the umask. * * H5F_ACC_EXCL: This function will fail if the file already * exists. * * H5F_ACC_TRUNC: Truncate the file to a zero-length file as it * is opened. This allows existing files to be * overwritten. * * The KEY argument is initialized with data which is unique to * this file. Opening the same file (even by a different name) * should return the same key. * * This is a virtual function only; the actual open operation is * performed by the subclass. This function will fail if the * subclass hasn't defined an open method. * * Errors: * IO CANTOPENFILE Open failed. * * Return: Success: Pointer to the new file descriptor. * * Failure: NULL * * Programmer: Robb Matzke * Wednesday, October 22, 1997 * * Modifications: * *------------------------------------------------------------------------- */ H5F_low_t * H5F_low_open(const H5F_low_class_t *type, const char *name, const H5F_access_t *access_parms, uintn flags, H5F_search_t *key/*out*/) { H5F_low_t *lf = NULL; FUNC_ENTER(H5F_low_open, NULL); assert(type && type->open); assert(name && *name); if (NULL == (lf = (type->open) (name, access_parms, flags, key))) { HRETURN_ERROR(H5E_IO, H5E_CANTOPENFILE, NULL, "open failed"); } lf->type = type; FUNC_LEAVE(lf); } /*------------------------------------------------------------------------- * Function: H5F_low_close * * Purpose: Closes a low-level file. The subclass should free all * resources used by the file descriptor but should not free the * file descriptor itself. The close method in the subclass is * optional; lack of a close method results in only the file * descriptor being freed. * * It is safe to call this function with a null pointer for the * file descriptor. This function returns a null pointer that * the caller can assign to the file descriptor pointer as it's * closed like `desc=H5F_low_close(desc)'. * * Errors: * IO CLOSEERROR Close failed. * * Return: Success: NULL * * Failure: NULL * * Programmer: Robb Matzke * Wednesday, October 22, 1997 * * Modifications: * *------------------------------------------------------------------------- */ H5F_low_t * H5F_low_close(H5F_low_t *lf, const H5F_access_t *access_parms) { FUNC_ENTER(H5F_low_close, NULL); if (lf) { if ((lf->type->close) (lf, access_parms) < 0) { H5MM_xfree(lf); HRETURN_ERROR(H5E_IO, H5E_CLOSEERROR, NULL, "close failed"); } H5MM_xfree(lf); } FUNC_LEAVE(NULL); } /*------------------------------------------------------------------------- * Function: H5F_low_read * * Purpose: Reads SIZE bytes of data beginning at address ADDR of the * file LF and puts the result in BUF. Behavior when reading * past the logical or physical end of file is to return zeros * for that part of the request. * * This is only a virtual function; the subclass must define a * read method or this function will fail. * * Errors: * IO READERROR Read failed. * IO UNSUPPORTED No read method. * * Return: Non-negative on success/Negative on failure * * Programmer: Robb Matzke * Wednesday, October 22, 1997 * * Modifications: * Albert Cheng, 1998-06-02 * Added XFER_MODE argument. * * Robb Matzke, 1999-07-28 * The ADDR argument is passed by value. *------------------------------------------------------------------------- */ herr_t H5F_low_read(H5F_low_t *lf, const H5F_access_t *access_parms, const H5F_xfer_t *xfer_parms, haddr_t addr, size_t size, uint8_t *buf/*out*/) { herr_t ret_value = FAIL; FUNC_ENTER(H5F_low_read, FAIL); assert(lf && lf->type); assert(H5F_addr_defined(addr)); assert(buf); if (lf->type->read) { if ((ret_value = (lf->type->read) (lf, access_parms, xfer_parms, addr, size, buf)) < 0) { HRETURN_ERROR(H5E_IO, H5E_READERROR, ret_value, "read failed"); } } else { HRETURN_ERROR(H5E_IO, H5E_UNSUPPORTED, FAIL, "no read method"); } FUNC_LEAVE(ret_value); } /*------------------------------------------------------------------------- * Function: H5F_low_write * * Purpose: Writes SIZE bytes of data from BUF into the file LF beginning * at address ADDR of the file. Writing past the logical or * physical end of file causes the file to be extended. * * This is a virtual function only; if the subclass doesn't * define a write method then this function will fail. * * Errors: * IO UNSUPPORTED No write method. * IO WRITEERROR Write failed. * * Return: Non-negative on success/Negative on failure * * Programmer: Robb Matzke * Wednesday, October 22, 1997 * * Modifications: * Albert Cheng, 1998-06-02 * Added XFER_MODE argument. * * rky, 1998-08-16 * Accommodate fancy MPI derived datatype writes. * * rky, 1998-09-02 * For non-block parallel writes, don't change value of lf->eof. * * Robb Matzke, 1999-07-28 * The ADDR argument is passed by value. *------------------------------------------------------------------------- */ herr_t H5F_low_write(H5F_low_t *lf, const H5F_access_t *access_parms, const H5F_xfer_t *xfer_parms, haddr_t addr, size_t size, const uint8_t *buf) { herr_t ret_value = FAIL; haddr_t tmp_addr; FUNC_ENTER(H5F_low_write, FAIL); assert(lf && lf->type); assert(H5F_addr_defined(addr)); assert(buf); /* check for writing past the end of file marker */ tmp_addr = addr + (hsize_t)size; if (H5F_addr_gt(tmp_addr, lf->eof)) HRETURN_ERROR(H5E_IO, H5E_OVERFLOW, ret_value, "write past end of logical file"); /* Check if the last byte of the logical file has been written */ if (!lf->eof_written && H5F_addr_eq(tmp_addr, lf->eof)) lf->eof_written=1; /* Write the data */ if (lf->type->write) { if ((ret_value = (lf->type->write) (lf, access_parms, xfer_parms, addr, size, buf)) < 0) { HRETURN_ERROR(H5E_IO, H5E_WRITEERROR, ret_value, "write failed"); } } else { HRETURN_ERROR(H5E_IO, H5E_UNSUPPORTED, FAIL, "no write method"); } FUNC_LEAVE(ret_value); } /*------------------------------------------------------------------------- * Function: H5F_low_flush * * Purpose: Flushes file buffers to disk. For instance, the stdio.h * driver would call fflush(). Flushing also insures that the * file exists to the current logical EOF (the library maintains * a notion of EOF which is independent of the physical EOF) by * reading and writing the last byte. On some systems, this * allocates a single block at the end of the file while on * other systems it allocates all blocks up to the end of the * file. Extending the physical file is necessary because * H5F_open() checks for truncated files. * * Return: Non-negative on success/Negative on failure * * Programmer: Robb Matzke * Monday, November 10, 1997 * * Modifications: * rky 980828 Only p0 writes metadata to disk. * *------------------------------------------------------------------------- */ herr_t H5F_low_flush(H5F_low_t *lf, const H5F_access_t *access_parms) { haddr_t last_byte; uint8_t buf[1]; FUNC_ENTER(H5F_low_flush, FAIL); assert(lf && lf->type); /* Make sure the last block of the file has been allocated on disk */ last_byte = 0; if (!lf->eof_written && H5F_addr_defined(lf->eof) && H5F_addr_gt(lf->eof, last_byte)) { last_byte = lf->eof; last_byte -= 1; if (H5F_low_read(lf, access_parms, &H5F_xfer_dflt, last_byte, 1, buf) >= 0) { #ifdef HAVE_PARALLEL H5F_mpio_tas_allsame( lf, TRUE ); /* only p0 will write */ #endif /* HAVE_PARALLEL */ H5F_low_write(lf, access_parms, &H5F_xfer_dflt, last_byte, 1, buf); } else HRETURN_ERROR(H5E_IO, H5E_READERROR, FAIL, "low level flush failed"); } /* Invoke the subclass the flush method */ if (lf->type->flush) { if ((lf->type->flush) (lf, access_parms) < 0) { HRETURN_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "low level flush failed"); } } FUNC_LEAVE(SUCCEED); } /*------------------------------------------------------------------------- * Function: H5F_low_size * * Purpose: Returns the current logical size of the file in bytes. This * may differ from the physical size of the file (most * subclasses extend the physical file size during the write * operation instead of the alloc operation). * * The next absolute file address is returned through the * EOF argument. This is the address of the logical end of * file (that is, the address of the first byte past the last * byte which is logically in the file). * * Warning: The return value type may not be large enough to represent * the true size of the file. In such cases, the maximum * possible size is returned. It is better to look at the EOF * output argument to determine the total size. * * Errors: * IO UNSUPPORTED No size method. * * Return: Success: Current size of file * * Failure: 0 * * Programmer: Robb Matzke * Wednesday, October 22, 1997 * * Modifications: * *------------------------------------------------------------------------- */ hsize_t H5F_low_size(H5F_low_t *lf, haddr_t *eof_p/*out*/) { hsize_t size = (hsize_t)(-1); /*max possible size */ FUNC_ENTER(H5F_low_size, 0); assert(lf && lf->type); assert(eof_p); *eof_p = lf->eof; if (*eof_p < size) size = *eof_p; FUNC_LEAVE(size); } /*------------------------------------------------------------------------- * Function: H5F_low_access * * Purpose: Determines if a file can be accessed in a particular way by a * particular subclass. The access modes for a file are the * same as those of access(2), namely * * F_OK: determines if the file (or all parts of a multi-part * file) exists. * * R_OK: determines if the file (or all parts of a multi-part * file) are readable. * * W_OK: determines if the file (or all parts of a multi-part * file) are writable. * * If a subclass doesn't define an access method, then we treat * the name as if it were a local Unix file and test * accessibility with the access(2) function. The KEY is * returned as a device number and i-node pair. * * Return: Success: TRUE or FALSE. If TRUE, then KEY is * initialized with data that makes this file * unique (same value as H5F_low_open). * * Failure: FAIL, KEY is undefined. * * Programmer: Robb Matzke * Friday, October 24, 1997 * * Modifications: * *------------------------------------------------------------------------- */ htri_t H5F_low_access(const H5F_low_class_t *type, const char *name, const H5F_access_t *access_parms, int mode, H5F_search_t *key/*out*/) { htri_t ret_value; struct stat sb; FUNC_ENTER(H5F_low_size, FAIL); assert(type); if (type->access) { ret_value = (type->access) (name, access_parms, mode, key /*out*/); } else { ret_value = (0 == HDaccess(name, mode) ? TRUE : FALSE); if (key) { #ifdef WIN32 int fd; HFILE filehandle; struct _BY_HANDLE_FILE_INFORMATION fileinfo; int results; fd = HDopen(name,_O_RDONLY,0); filehandle = _get_osfhandle(fd); results = GetFileInformationByHandle(filehandle, &fileinfo); /*returns a 0 on failure*/ if (!results) { ret_value = FALSE; } else { HDstat(name,&sb); key->dev = sb.st_dev; key->ino = 0; key->fileindexhi = fileinfo.nFileIndexHigh; key->fileindexlo = fileinfo.nFileIndexLow; } HDclose(fd); #else HDstat(name, &sb); key->dev = sb.st_dev; key->ino = sb.st_ino; #endif } } FUNC_LEAVE(ret_value); } /*------------------------------------------------------------------------- * Function: H5F_low_extend * * Purpose: Increases the logical size of a file by moving the logical * end of file marker. A subclass can override this function by * providing its own allocation method. * * Return: Success: Non-negative. The address of the old * end-of-file is returned through the ADDR_P * argument and the logical size of the file has * been extended by SIZE bytes. * * Failure: Negative. * * Programmer: Robb Matzke * Thursday, November 13, 1997 * * Modifications: * *------------------------------------------------------------------------- */ herr_t H5F_low_extend(H5F_low_t *lf, const H5F_access_t *access_parms, intn op, hsize_t size, haddr_t *addr_p/*out*/) { FUNC_ENTER(H5F_low_alloc, FAIL); assert(lf); assert(size > 0); assert(addr_p); /* Reset the EOF written flag */ lf->eof_written=0; if (lf->type->extend) { if ((lf->type->extend) (lf, access_parms, op, size, addr_p/*out*/)<0) { HRETURN_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to extend file"); } } else { *addr_p = lf->eof; lf->eof += size; } FUNC_LEAVE(SUCCEED); } /*------------------------------------------------------------------------- * Function: H5F_low_alloc * * Purpose: Determines if a free block BLK can satisfy a request for SIZE * bytes of memory from file F. If SIZE >= THRESH then the * memory must be aligned on an ALIGN-byte boundary. Alignment * is wrt the relative file addresses (that is, the size of the * user-defined block at the beginning of the file is subtracted * from the addresses before aligning them). * * Return: Success: Positive if the free block exactly satisfies * the request; zero if the free block * over-satisfies the request. In either case, * ADDR will be the address within the free * block where the request can be satisfied. * * Failure: Negative with the output value of ADDR_P * undefined. * * Programmer: Robb Matzke * Tuesday, June 9, 1998 * * Modifications: * *------------------------------------------------------------------------- */ intn H5F_low_alloc (H5F_low_t *lf, intn op, hsize_t alignment, hsize_t threshold, hsize_t size, H5MF_free_t *blk, haddr_t *addr_p/*out*/) { intn ret_value = FAIL; hsize_t wasted; FUNC_ENTER (H5F_low_alloc, FAIL); assert (lf); assert (alignment>0); assert (size>0); assert (blk); assert (addr_p); if (lf->type->alloc) { ret_value = (lf->type->alloc)(lf, op, alignment, threshold, size, blk, addr_p/*out*/); } else { if (size>=threshold) { wasted = blk->addr % alignment; } else { wasted = 0; } if (0==wasted && size==blk->size) { /* exact match */ *addr_p = blk->addr; ret_value = 1; } else if (blk->size>wasted && blk->size-wasted>=size) { /* over-satisfied */ *addr_p = blk->addr + wasted; ret_value = 0; } } FUNC_LEAVE (ret_value); } /*------------------------------------------------------------------------- * Function: H5F_low_seteof * * Purpose: Sets the logical end-of-file to the specified address. * * Return: Non-negative on success/Negative on failure * * Programmer: Robb Matzke * Thursday, November 13, 1997 * * Modifications: * Robb Matzke, 1999-07-28 * The ADDR argument is passed by value. *------------------------------------------------------------------------- */ herr_t H5F_low_seteof(H5F_low_t *lf, haddr_t addr) { FUNC_ENTER(H5F_low_seteof, FAIL); assert(lf); assert(H5F_addr_defined(addr)); lf->eof = addr; FUNC_LEAVE(SUCCEED); } /*------------------------------------------------------------------------- * Function: H5F_addr_encode * * Purpose: Encodes an address into the buffer pointed to by *PP and * then increments the pointer to the first byte after the * address. An undefined value is stored as all 1's. * * Return: void * * Programmer: Robb Matzke * Friday, November 7, 1997 * * Modifications: * Robb Matzke, 1999-07-28 * The ADDR argument is passed by value. *------------------------------------------------------------------------- */ void H5F_addr_encode(H5F_t *f, uint8_t **pp/*in,out*/, haddr_t addr) { uintn i; haddr_t tmp; assert(f); assert(pp && *pp); if (H5F_addr_defined(addr)) { tmp = addr; for (i=0; i>= 8; } assert("overflow" && 0 == tmp); } else { for (i=0; ioffset and how it is being called. * *------------------------------------------------------------------------- */ herr_t H5F_addr_pack(H5F_t UNUSED *f, haddr_t *addr_p/*out*/, const unsigned long objno[2]) { assert(f); assert(objno); assert(addr_p); *addr_p = objno[0]; #if SIZEOF_LONG