Files
hdf5/src/H5Flow.c
Robb Matzke faca6fbaa8 [svn-r145] ./src/H5Osdtyp.c -> H5Odtype.c
./src/H5Osdim.c		-> H5Osdspace.c
./src/Makefile.in
	Changed the names of these files to better reflect what they
	actually do.

./src/H5.c
./src/H5AC.c
./src/H5B.c
./src/H5C.c
./src/H5D.c
./src/H5E.c
./src/H5Eprivate.h
./src/H5Epublic.h
./src/H5F.c
./src/H5Fcore.c
./src/H5Ffamily.c
./src/H5Fistore.c
./src/H5Flow.c
./src/H5Fsec2.c
./src/H5Fsplit.c
./src/H5Fstdio.c
./src/H5G.c
./src/H5Gent.c
./src/H5Gnode.c
./src/H5Gshad.c
./src/H5Gstab.c
./src/H5H.c
./src/H5M.c
./src/H5MF.c
./src/H5O.c
./src/H5Osdtyp.c (./src/H5Odtype.c)
./src/H5P.c
./src/H5T.c
./src/H5detect.c
./src/H5private.h
	Added an argument to the HRETURN_ERROR(), HGOTO_ERROR(), and
	HERROR() macros which is a string error message.  This allows
	us to give extra information which can't be represented by the
	major and minor error numbers.  This information was
	previously in comments just before or after the macro call.
	The string isn't currently used, but I'm planning to change
	the test files so they print an error trace when something
	fails.  This should make debugging a little faster since it's
	often obvious what's wrong if we could just see the error
	stack without even having to start a debugger.
1997-12-11 16:35:46 -05:00

841 lines
21 KiB
C
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* Copyright (C) 1997 NCSA
* All rights reserved.
*
* Programmer: Robb Matzke <matzke@viper.llnl.gov>
* 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 <H5private.h>
#include <H5Eprivate.h>
#include <H5Fprivate.h>
#include <H5MMprivate.h>
#include <sys/types.h>
#include <sys/stat.h>
#define PABLO_MASK H5F_low
static hbool_t interface_initialize_g = FALSE;
#define INTERFACE_INIT NULL
/*-------------------------------------------------------------------------
* 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, 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, 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)
{
FUNC_ENTER (H5F_low_close, NULL);
if (lf) {
if ((lf->type->close)(lf)<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: Success: SUCCEED
*
* Failure: FAIL
*
* Programmer: Robb Matzke
* Wednesday, October 22, 1997
*
* Modifications:
*
*-------------------------------------------------------------------------
*/
herr_t
H5F_low_read (H5F_low_t *lf, const haddr_t *addr, size_t size,
uint8 *buf/*out*/)
{
herr_t ret_value = FAIL;
FUNC_ENTER (H5F_low_read, FAIL);
assert (lf && lf->type);
assert (addr && H5F_addr_defined (addr));
assert (buf);
if (lf->type->read) {
if ((ret_value = (lf->type->read)(lf, 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: Success: SUCCEED
*
* Failure: FAIL
*
* Programmer: Robb Matzke
* Wednesday, October 22, 1997
*
* Modifications:
*
*-------------------------------------------------------------------------
*/
herr_t
H5F_low_write (H5F_low_t *lf, const haddr_t *addr, size_t size,
const uint8 *buf)
{
herr_t ret_value = FAIL;
haddr_t tmp_addr;
FUNC_ENTER (H5F_low_write, FAIL);
assert (lf && lf->type);
assert (addr && H5F_addr_defined (addr));
assert (buf);
/* Extend the file eof marker if we write past it */
tmp_addr = *addr;
H5F_addr_inc (&tmp_addr, size);
if (H5F_addr_gt (&tmp_addr, &(lf->eof))) {
fprintf (stderr, "HDF5-DIAG: extending file w/o allocation\n");
lf->eof = tmp_addr;
}
/* Write the data */
if (lf->type->write) {
if ((ret_value = (lf->type->write)(lf, 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: Success: SUCCEED
*
* Failure: FAIL
*
* Programmer: Robb Matzke
* Monday, November 10, 1997
*
* Modifications:
*
*-------------------------------------------------------------------------
*/
herr_t
H5F_low_flush (H5F_low_t *lf)
{
haddr_t last_byte;
uint8 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 */
H5F_addr_reset (&last_byte);
if (H5F_addr_defined (&(lf->eof)) && H5F_addr_gt (&(lf->eof), &last_byte)) {
last_byte = lf->eof;
last_byte.offset -= 1;
if (H5F_low_read (lf, &last_byte, 1, buf)>=0) {
H5F_low_write (lf, &last_byte, 1, buf);
}
}
/* Invoke the subclass the flush method */
if (lf->type->flush) {
if ((lf->type->flush)(lf)<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 (size_t) 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:
*
*-------------------------------------------------------------------------
*/
size_t
H5F_low_size (H5F_low_t *lf, haddr_t *eof/*out*/)
{
size_t size = (size_t)(-1); /*max possible size*/
FUNC_ENTER (H5F_low_size, 0);
assert (lf && lf->type);
assert (eof);
*eof = lf->eof;
if (eof->offset < size) size = eof->offset;
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:
*
*-------------------------------------------------------------------------
*/
hbool_t
H5F_low_access (const H5F_low_class_t *type, const char *name, int mode,
H5F_search_t *key/*out*/)
{
hbool_t ret_value;
struct stat sb;
FUNC_ENTER (H5F_low_size, 0);
assert (type);
if (type->access) {
ret_value = (type->access)(name, mode, key/*out*/);
} else {
ret_value = (0==access (name, mode));
if (key) {
stat (name, &sb);
key->dev = sb.st_dev;
key->ino = sb.st_ino;
}
}
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: SUCCEED, the address of the old end-of-file
* is returned through the ADDR argument and the
* logical size of the file has been extended by
* SIZE bytes.
*
* Failure: FAIL
*
* Programmer: Robb Matzke
* Thursday, November 13, 1997
*
* Modifications:
*
*-------------------------------------------------------------------------
*/
herr_t
H5F_low_extend (H5F_low_t *lf, intn op, size_t size, haddr_t *addr/*out*/)
{
FUNC_ENTER (H5F_low_alloc, FAIL);
assert (lf);
assert (size>0);
assert (addr);
if (lf->type->extend) {
if ((lf->type->extend)(lf, op, size, addr/*out*/)<0) {
HRETURN_ERROR (H5E_RESOURCE, H5E_NOSPACE, FAIL,
"unable to extend file");
}
} else {
*addr = lf->eof;
H5F_addr_inc (&(lf->eof), size);
}
FUNC_LEAVE (SUCCEED);
}
/*-------------------------------------------------------------------------
* Function: H5F_low_seteof
*
* Purpose: Sets the logical end-of-file to the specified address.
*
* Return: Success: SUCCEED
*
* Failure: FAIL
*
* Programmer: Robb Matzke
* Thursday, November 13, 1997
*
* Modifications:
*
*-------------------------------------------------------------------------
*/
herr_t
H5F_low_seteof (H5F_low_t *lf, const haddr_t *addr)
{
FUNC_ENTER (H5F_low_seteof, FAIL);
assert (lf);
assert (addr && H5F_addr_defined (addr));
lf->eof = *addr;
FUNC_LEAVE (SUCCEED);
}
/*-------------------------------------------------------------------------
* Function: H5F_addr_cmp
*
* Purpose: Compares two addresses.
*
* Return: Success: <0 if A1<A2
* =0 if A1=A2
* >0 if A1>A2
*
* Failure: never fails
*
* Programmer: Robb Matzke
* Friday, November 7, 1997
*
* Modifications:
*
*-------------------------------------------------------------------------
*/
intn
H5F_addr_cmp (const haddr_t *a1, const haddr_t *a2)
{
FUNC_ENTER (H5F_addr_cmp, FAIL);
assert (a1 && H5F_addr_defined (a1));
assert (a2 && H5F_addr_defined (a2));
if (a1->offset<a2->offset) HRETURN (-1);
if (a1->offset>a2->offset) HRETURN (1);
FUNC_LEAVE (0);
}
/*-------------------------------------------------------------------------
* Function: H5F_addr_undef
*
* Purpose: Cause an address to become undefined.
*
* Return: void
*
* Programmer: Robb Matzke
* Friday, November 7, 1997
*
* Modifications:
*
*-------------------------------------------------------------------------
*/
void
H5F_addr_undef (haddr_t *addr/*out*/)
{
assert (addr);
addr->offset = -1;
}
/*-------------------------------------------------------------------------
* Function: H5F_addr_defined
*
* Purpose: Determines if an address has a defined value.
*
* Return: Success: TRUE or FALSE
*
* Failure: FAIL
*
* Programmer: Robb Matzke
* Friday, November 7, 1997
*
* Modifications:
*
*-------------------------------------------------------------------------
*/
hbool_t
H5F_addr_defined (const haddr_t *addr)
{
FUNC_ENTER (H5F_addr_defined, FAIL);
FUNC_LEAVE (-1!=addr->offset && addr->offset>=0);
}
/*-------------------------------------------------------------------------
* Function: H5F_addr_reset
*
* Purpose: Reset the address to zero.
*
* Return: void
*
* Programmer: Robb Matzke
* Friday, November 7, 1997
*
* Modifications:
*
*-------------------------------------------------------------------------
*/
void
H5F_addr_reset (haddr_t *addr/*out*/)
{
assert (addr);
addr->offset = 0;
}
/*-------------------------------------------------------------------------
* Function: H5F_addr_zerop
*
* Purpose: Determines if an address is zero.
*
* Return: Success: TRUE or FALSE
*
* Failure: FAIL
*
* Programmer: Robb Matzke
* Friday, November 7, 1997
*
* Modifications:
*
*-------------------------------------------------------------------------
*/
hbool_t
H5F_addr_zerop (const haddr_t *addr)
{
FUNC_ENTER (H5F_addr_zerop, FAIL);
FUNC_LEAVE (0==addr->offset);
}
/*-------------------------------------------------------------------------
* 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:
*
*-------------------------------------------------------------------------
*/
void
H5F_addr_encode (H5F_t *f, uint8 **pp, const haddr_t *addr)
{
int i;
haddr_t tmp;
assert (f);
assert (pp && *pp);
assert (addr);
if (H5F_addr_defined (addr)) {
tmp = *addr;
for (i=0; i<H5F_SIZEOF_ADDR (f); i++) {
*(*pp)++ = tmp.offset & 0xff;
tmp.offset >>= 8;
}
assert ("overflow" && 0==tmp.offset);
} else {
for (i=0; i<H5F_SIZEOF_ADDR (f); i++) {
*(*pp)++ = 0xff;
}
}
}
/*-------------------------------------------------------------------------
* Function: H5F_addr_decode
*
* Purpose: Decodes an address from the buffer pointed to by *PP and
* updates the pointer to point to the next byte after the
* address.
*
* If the value read is all 1's then the address is returned
* with an undefined value.
*
* Return: void
*
* Programmer: Robb Matzke
* Friday, November 7, 1997
*
* Modifications:
*
*-------------------------------------------------------------------------
*/
void
H5F_addr_decode (H5F_t *f, const uint8 **pp, haddr_t *addr/*out*/)
{
int i;
haddr_t tmp;
uint8 c;
hbool_t all_zero = TRUE;
assert (f);
assert (pp && *pp);
assert (addr);
addr->offset = 0;
for (i=0; i<H5F_SIZEOF_ADDR (f); i++) {
c = *(*pp)++;
if (c!=0xff) all_zero = FALSE;
if (i<sizeof(addr->offset)) {
tmp.offset = c;
tmp.offset <<= i*8; /*use tmp to get casting right*/
addr->offset |= tmp.offset;
} else if (!all_zero) {
assert (0==**pp); /*overflow*/
}
}
if (all_zero) H5F_addr_undef (addr);
}
/*-------------------------------------------------------------------------
* Function: H5F_addr_print
*
* Purpose: Print an address
*
* Return: void
*
* Programmer: Robb Matzke
* Friday, November 7, 1997
*
* Modifications:
*
*-------------------------------------------------------------------------
*/
void
H5F_addr_print (FILE *stream, const haddr_t *addr)
{
haddr_t tmp;
assert (stream);
assert (addr);
if (H5F_addr_defined (addr)) {
/*
* It would be nice if we could use the `%Lu', `%llu', or `%qu', but
* we don't know which is supported. So we split the address into a
* low 4-bytes and a high 4-bytes. If the high 4-bytes are non-zero
* then we print the address in hexadecimal, otherwise we use decimal.
*/
tmp = *addr;
tmp.offset >>= 32;
if (tmp.offset) {
fprintf (stream, "0x%08lx%08lx",
(unsigned long)(tmp.offset),
(unsigned long)(addr->offset & 0xffffffff));
} else {
fprintf (stream, "%lu", (unsigned long)(addr->offset));
}
} else {
fprintf (stream, "UNDEF");
}
}
/*-------------------------------------------------------------------------
* Function: H5F_addr_pow2
*
* Purpose: Returns an address which is a power of two.
*
* Return: void
*
* Programmer: Robb Matzke
* Friday, November 7, 1997
*
* Modifications:
*
*-------------------------------------------------------------------------
*/
void
H5F_addr_pow2 (uintn n, haddr_t *addr/*out*/)
{
assert (n>=0);
assert (addr);
assert (n<8*sizeof(addr->offset));
addr->offset = 1;
addr->offset <<= n;
}
/*-------------------------------------------------------------------------
* Function: H5F_addr_inc
*
* Purpose: Increments an address by some number of bytes.
*
* Return: void
*
* Programmer: Robb Matzke
* Friday, November 7, 1997
*
* Modifications:
*
*-------------------------------------------------------------------------
*/
void
H5F_addr_inc (haddr_t *addr/*in,out*/, size_t inc)
{
assert (addr && H5F_addr_defined (addr));
assert (addr->offset<=addr->offset+inc);
addr->offset += inc;
}
/*-------------------------------------------------------------------------
* Function: H5F_addr_add
*
* Purpose: Adds two addresses and puts the result in the first argument.
*
* Return: void
*
* Programmer: Robb Matzke
* Friday, November 7, 1997
*
* Modifications:
*
*-------------------------------------------------------------------------
*/
void
H5F_addr_add (haddr_t *a1/*in,out*/, const haddr_t *a2)
{
assert (a1 && H5F_addr_defined (a1));
assert (a2 && H5F_addr_defined (a2));
a1->offset += a2->offset;
}
/*-------------------------------------------------------------------------
* Function: H5F_addr_hash
*
* Purpose: Computes a hash value of an address between 0 and MOD-1,
* inclusive.
*
* Return: Success: The hash value
*
* Failure: never fails
*
* Programmer: Robb Matzke
* Friday, November 7, 1997
*
* Modifications:
*
*-------------------------------------------------------------------------
*/
uintn
H5F_addr_hash (const haddr_t *addr, uintn mod)
{
assert (addr && H5F_addr_defined (addr));
assert (mod>0);
return addr->offset % mod; /*ignore file number*/
}