/* * Copyright (C) 1997 NCSA * All rights reserved. * * Programmer: Robb Matzke * Wednesday, October 22, 1997 * * Purpose: This is the Posix stdio.h I/O subclass of H5Flow. */ #include #include #include #include #include #include #include #define PABLO_MASK H5F_sec2 static hbool_t interface_initialize_g = FALSE; static H5F_low_t *H5F_stdio_open (const char *name, uintn flags, H5F_search_t *key); static herr_t H5F_stdio_close (H5F_low_t *lf); static herr_t H5F_stdio_read (H5F_low_t *lf, haddr_t addr, size_t size, uint8 *buf); static herr_t H5F_stdio_write (H5F_low_t *lf, haddr_t addr, size_t size, const uint8 *buf); static herr_t H5F_stdio_flush (H5F_low_t *lf); static size_t H5F_stdio_size (H5F_low_t *lf); const H5F_low_class_t H5F_LOW_STDIO[1] = {{ NULL, /* use default access(2) func */ H5F_stdio_open, /* open method */ H5F_stdio_close, /* close method */ H5F_stdio_read, /* read method */ H5F_stdio_write, /* write method */ H5F_stdio_flush, /* flush method */ H5F_stdio_size, /* file size method */ }}; /*------------------------------------------------------------------------- * Function: H5F_stdio_open * * Purpose: Opens a file with name NAME. The FLAGS are a bit field with * the possible values defined in H5F_low_open(). * * Bugs: H5F_ACC_EXCL has a race condition. * * Errors: * IO CANTOPENFILE File doesn't exist and CREAT wasn't * specified. * IO CANTOPENFILE Fopen failed. * IO FILEEXISTS File exists but CREAT and EXCL were * specified. * * Return: Success: Low-level file pointer * * Failure: NULL * * Programmer: Robb Matzke * Wednesday, October 22, 1997 * * Modifications: * *------------------------------------------------------------------------- */ static H5F_low_t * H5F_stdio_open (const char *name, uintn flags, H5F_search_t *key) { H5F_low_t *lf=NULL; FILE *f=NULL; struct stat sb; FUNC_ENTER (H5F_stdio_open, NULL, NULL); if (access (name, F_OK)<0) { if ((flags & H5F_ACC_CREAT) && (flags & H5F_ACC_WRITE)) { f = fopen (name, "wb+"); } else { /* File doesn't exist and CREAT wasn't specified */ HRETURN_ERROR (H5E_IO, H5E_CANTOPENFILE, NULL); } } else if ((flags & H5F_ACC_CREAT) && (flags & H5F_ACC_EXCL)) { /* File exists but CREAT and EXCL were specified */ HRETURN_ERROR (H5E_IO, H5E_FILEEXISTS, NULL); } else if (flags & H5F_ACC_WRITE) { if (flags & H5F_ACC_TRUNC) f = fopen (name, "wb+"); else f = fopen (name, "rb+"); } else { f = fopen (name, "rb"); } if (!f) HRETURN_ERROR (H5E_IO, H5E_CANTOPENFILE, NULL); /*fopen failed*/ /* Build the return value */ lf = H5MM_xcalloc (1, sizeof(H5F_low_t)); lf->u.stdio.f = f; lf->u.stdio.op = H5F_OP_SEEK; lf->u.stdio.cur = 0; /* The unique key */ if (key) { fstat (fileno (f), &sb); key->dev = sb.st_dev; key->ino = sb.st_ino; } FUNC_LEAVE (lf); } /*------------------------------------------------------------------------- * Function: H5F_stdio_close * * Purpose: Closes a file. * * Errors: * IO CLOSEERROR Close failed. * * Return: Success: SUCCEED * * Failure: FAIL * * Programmer: Robb Matzke * Wednesday, October 22, 1997 * * Modifications: * *------------------------------------------------------------------------- */ static herr_t H5F_stdio_close (H5F_low_t *lf) { FUNC_ENTER (H5F_stdio_close, NULL, FAIL); if (fclose (lf->u.stdio.f)<0) { HRETURN_ERROR (H5E_IO, H5E_CLOSEERROR, FAIL); /*close failed*/ } lf->u.stdio.f = NULL; FUNC_LEAVE (SUCCEED); } /*------------------------------------------------------------------------- * Function: H5F_stdio_read * * Purpose: Reads SIZE bytes beginning at address ADDR in file LF and * places them in buffer BUF. Reading past the end of the * file returns zeros instead of failing. * * Errors: * IO READERROR Fread failed. * IO SEEKERROR Fseek failed. * * Return: Success: SUCCEED * * Failure: FAIL * * Programmer: Robb Matzke * Wednesday, October 22, 1997 * * Modifications: * *------------------------------------------------------------------------- */ static herr_t H5F_stdio_read (H5F_low_t *lf, haddr_t addr, size_t size, uint8 *buf) { size_t n; FUNC_ENTER (H5F_stdio_read, NULL, FAIL); /* * Seek to the correct file position. */ if (!H5F_OPT_SEEK || lf->u.stdio.op!=H5F_OP_READ || lf->u.stdio.cur!=addr) { if (fseek (lf->u.stdio.f, addr, SEEK_SET)<0) { HRETURN_ERROR (H5E_IO, H5E_SEEKERROR, FAIL); /*fseek failed*/ } lf->u.stdio.cur = addr; } /* * Read the data. Since we're reading single-byte values, a partial read * will advance the file position by N. If N is negative or an error * occurs then the file position is undefined. */ n = fread (buf, 1, size, lf->u.stdio.f); if (n<=0 && ferror (lf->u.stdio.f)) { lf->u.stdio.op = H5F_OP_UNKNOWN; HRETURN_ERROR (H5E_IO, H5E_READERROR, FAIL); /*fread failed*/ } else if (nu.stdio.op = H5F_OP_READ; lf->u.stdio.cur = addr + n; FUNC_LEAVE (SUCCEED); } /*------------------------------------------------------------------------- * Function: H5F_stdio_write * * Purpose: Writes SIZE bytes from the beginning of BUF into file LF at * file address ADDR. * * Errors: * IO SEEKERROR Fseek failed. * IO WRITEERROR Fwrite failed. * * Return: Success: SUCCEED * * Failure: FAIL * * Programmer: Robb Matzke * Wednesday, October 22, 1997 * * Modifications: * *------------------------------------------------------------------------- */ static herr_t H5F_stdio_write (H5F_low_t *lf, haddr_t addr, size_t size, const uint8 *buf) { int status; FUNC_ENTER (H5F_stdio_write, NULL, FAIL); /* * Seek to the correct file position. */ if (!H5F_OPT_SEEK || lf->u.stdio.op!=H5F_OP_WRITE || lf->u.stdio.cur!=addr) { if (fseek (lf->u.stdio.f, addr, SEEK_SET)<0) { HRETURN_ERROR (H5E_IO, H5E_SEEKERROR, FAIL); /*fseek failed*/ } lf->u.stdio.cur = addr; } /* * Write the buffer. On successful return, the file position will be * advanced by the number of bytes read. Otherwise nobody knows where it * is. */ status = fwrite (buf, 1, size, lf->u.stdio.f); if (size != status) { lf->u.stdio.op = H5F_OP_UNKNOWN; HRETURN_ERROR (H5E_IO, H5E_WRITEERROR, FAIL); /*fwrite failed*/ } /* * Update seek optimizing data. */ lf->u.stdio.op = H5F_OP_WRITE; lf->u.stdio.cur = addr + size; FUNC_LEAVE (SUCCEED); } /*------------------------------------------------------------------------- * Function: H5F_stdio_flush * * Purpose: Makes sure that all data is on disk. * * Errors: * IO WRITEERROR Fflush failed. * * Return: Success: SUCCEED * * Failure: FAIL * * Programmer: Robb Matzke * Wednesday, October 22, 1997 * * Modifications: * *------------------------------------------------------------------------- */ static herr_t H5F_stdio_flush (H5F_low_t *lf) { FUNC_ENTER (H5F_stdio_flush, NULL, FAIL); /* * What happens to the file position? Is it guaranteed to be the same * after the fflush() as it was before? */ lf->u.stdio.op = H5F_OP_UNKNOWN; /* * Flush */ if (fflush (lf->u.stdio.f)<0) { HRETURN_ERROR (H5E_IO, H5E_WRITEERROR, FAIL); /*fflush failed*/ } FUNC_LEAVE (SUCCEED); } /*------------------------------------------------------------------------- * Function: H5F_stdio_size * * Purpose: Returns the current size of the file in bytes. * * Bugs: There is no way to determine if this function failed. * * Errors: * IO SEEKERROR Fseek failed. * * Return: Success: Size of file in bytes * * Failure: 0 * * Programmer: Robb Matzke * Wednesday, October 22, 1997 * * Modifications: * *------------------------------------------------------------------------- */ static size_t H5F_stdio_size (H5F_low_t *lf) { off_t size; FUNC_ENTER (H5F_stdio_size, NULL, 0); /* Seek to the end and get the file offset */ if (fseek (lf->u.stdio.f, 0, SEEK_END)<0) { HRETURN_ERROR (H5E_IO, H5E_SEEKERROR, 0); /*fseek failed*/ } size = ftell (lf->u.stdio.f); /* Update seek opt data */ lf->u.stdio.op = H5F_OP_SEEK; lf->u.stdio.cur = size; FUNC_LEAVE (size); }