diff options
author | Robb Matzke <matzke@llnl.gov> | 1998-07-13 15:35:21 (GMT) |
---|---|---|
committer | Robb Matzke <matzke@llnl.gov> | 1998-07-13 15:35:21 (GMT) |
commit | 614ae2dce6086a8966a26074f48644aa3c92f93c (patch) | |
tree | 9f7ddbf622c6403dd61ae4bb977dda94e75ac915 /tools | |
parent | b5189f738df7043790a254ed55263b08386dece8 (diff) | |
download | hdf5-614ae2dce6086a8966a26074f48644aa3c92f93c.zip hdf5-614ae2dce6086a8966a26074f48644aa3c92f93c.tar.gz hdf5-614ae2dce6086a8966a26074f48644aa3c92f93c.tar.bz2 |
[svn-r485] Changes since 19980710
----------------------
./Makefile.in
./config/commence.in
./config/conclude.in
./config/depend.in
./src/Makefile.in
./test/Makefile.in
Tests are no longer installed for `make install'. Added a new
target `make tests' that builds the tests but doesn't run them.
./configure.in
./configure [REGENERATED]
./src/H5config.h.in [REGENERATED]
Added detection of fork() and waitpid(). If present the
contants HAVE_FORK and HAVE_WAITPID will be defined in
H5config.h.
./test/dtypes.c
Minor tweaks for systems that don't have fork() or waitpid().
./MANIFEST
./tools [NEW]
./tools/Makefile.in [NEW]
./tools/h5debug.c [NEW]
./tools/h5import.c [NEW]
./tools/h5ls.c [NEW]
./tools/h5repart.c [NEW]
Added a tools directory and moved tools from the src directory
to here.
Diffstat (limited to 'tools')
-rw-r--r-- | tools/Makefile.in | 32 | ||||
-rw-r--r-- | tools/h5debug.c | 178 | ||||
-rw-r--r-- | tools/h5import.c | 119 | ||||
-rw-r--r-- | tools/h5ls.c | 197 | ||||
-rw-r--r-- | tools/h5repart.c | 388 |
5 files changed, 914 insertions, 0 deletions
diff --git a/tools/Makefile.in b/tools/Makefile.in new file mode 100644 index 0000000..1f93b00 --- /dev/null +++ b/tools/Makefile.in @@ -0,0 +1,32 @@ +# HDF5 Library Makefile(.in) +# +# Copyright (C) 1997 National Center for Supercomputing Applications. +# All rights reserved. +# +# +@COMMENCE@ + +# Add include directory to the C preprocessor flags. +CPPFLAGS=-I../src @CPPFLAGS@ + +# These are our main targets: +PROGS=h5debug h5import h5ls h5repart + +# Source and object files for programs... +PROG_SRC=h5debug.c h5import.c h5ls.c h5repart.c +PROG_OBJ=$(PROG_SRC:.c=.o) + +# How to build the programs... +h5debug: h5debug.o ../src/libhdf5.a + $(CC) $(CFLAGS) -o $@ h5debug.o ../src/libhdf5.a $(LIBS) + +h5import: h5import.o ../src/libhdf5.a + $(CC) $(CFLAGS) -o $@ h5import.o ../src/libhdf5.a $(LIBS) + +h5ls: h5ls.o ../src/libhdf5.a + $(CC) $(CFLAGS) -o $@ h5ls.o ../src/libhdf5.a $(LIBS) + +h5repart: h5repart.o ../src/libhdf5.a + $(CC) $(CFLAGS) -o $@ h5repart.o ../src/libhdf5.a $(LIBS) + +@CONCLUDE@ diff --git a/tools/h5debug.c b/tools/h5debug.c new file mode 100644 index 0000000..fdf21d9 --- /dev/null +++ b/tools/h5debug.c @@ -0,0 +1,178 @@ +/*------------------------------------------------------------------------- + * Copyright (C) 1997 National Center for Supercomputing Applications. + * All rights reserved. + * + *------------------------------------------------------------------------- + * + * Created: debug.c + * Jul 18 1997 + * Robb Matzke <matzke@llnl.gov> + * + * Purpose: Debugs an existing HDF5 file at a low level. + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +#include <H5private.h> +#include <H5Iprivate.h> +#include <H5Bprivate.h> +#include <H5Pprivate.h> +#include <H5Fprivate.h> +#include <H5Gprivate.h> +#include <H5HGprivate.h> +#include <H5HLprivate.h> +#include <H5Oprivate.h> + +#define INDENT 3 +#define VCOL 50 + + +/*------------------------------------------------------------------------- + * Function: main + * + * Usage: debug FILENAME [OFFSET] + * + * Return: Success: exit (0) + * + * Failure: exit (non-zero) + * + * Programmer: Robb Matzke + * matzke@llnl.gov + * Jul 18 1997 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +int +main(int argc, char *argv[]) +{ + hid_t fid, plist=H5P_DEFAULT; + H5F_t *f; + haddr_t addr; + uint8 sig[16]; + intn i, ndims; + herr_t status = SUCCEED; + haddr_t extra; + + /* + * Open the file and get the file descriptor. + */ + if (strchr (argv[1], '%')) { + plist = H5Pcreate (H5P_FILE_ACCESS); + H5Pset_family (plist, 0, H5P_DEFAULT); + } + if ((fid = H5Fopen(argv[1], H5F_ACC_RDONLY, plist)) < 0) { + fprintf(stderr, "cannot open file\n"); + HDexit(1); + } + if (NULL == (f = H5I_object(fid))) { + fprintf(stderr, "cannot obtain H5F_t pointer\n"); + HDexit(2); + } + + /* + * Parse command arguments. + */ + H5F_addr_reset(&addr); + H5F_addr_reset(&extra); + if (argc > 2) { + printf("New address: %s\n", argv[2]); + addr.offset = HDstrtoll(argv[2], NULL, 0); + } + if (argc > 3) { + extra.offset = HDstrtoll(argv[3], NULL, 0); + } + /* + * Read the signature at the specified file position. + */ + printf("Reading signature at address "); + H5F_addr_print(stdout, &addr); + printf(" (rel)\n"); + if (H5F_block_read(f, &addr, (hsize_t)sizeof(sig), H5D_XFER_DFLT, sig) < 0) { + fprintf(stderr, "cannot read signature\n"); + HDexit(3); + } + if (!HDmemcmp(sig, H5F_SIGNATURE, H5F_SIGNATURE_LEN)) { + /* + * Debug the boot block. + */ + status = H5F_debug(f, &addr, stdout, 0, VCOL); + + } else if (!HDmemcmp(sig, H5HL_MAGIC, H5HL_SIZEOF_MAGIC)) { + /* + * Debug a local heap. + */ + status = H5HL_debug(f, &addr, stdout, 0, VCOL); + + } else if (!HDmemcmp (sig, H5HG_MAGIC, H5HG_SIZEOF_MAGIC)) { + /* + * Debug a global heap collection. + */ + status = H5HG_debug (f, &addr, stdout, 0, VCOL); + + } else if (!HDmemcmp(sig, H5G_NODE_MAGIC, H5G_NODE_SIZEOF_MAGIC)) { + /* + * Debug a symbol table node. + */ + status = H5G_node_debug(f, &addr, stdout, 0, VCOL, &extra); + + } else if (!HDmemcmp(sig, H5B_MAGIC, H5B_SIZEOF_MAGIC)) { + /* + * Debug a B-tree. B-trees are debugged through the B-tree + * subclass. The subclass identifier is the byte immediately + * after the B-tree signature. + */ + H5B_subid_t subtype = (H5B_subid_t)sig[H5B_SIZEOF_MAGIC]; + + switch (subtype) { + case H5B_SNODE_ID: + status = H5G_node_debug(f, &addr, stdout, 0, VCOL, &extra); + break; + + case H5B_ISTORE_ID: + ndims = (int)extra.offset; + status = H5F_istore_debug (f, &addr, stdout, 0, VCOL, ndims); + break; + + default: + fprintf(stderr, "Unknown B-tree subtype %u\n", (unsigned) (subtype)); + HDexit(4); + } + + } else if (sig[0] == H5O_VERSION) { + /* + * This could be an object header. Since they don't have a signature + * it's a somewhat "ify" detection. + */ + status = H5O_debug(f, &addr, stdout, 0, VCOL); + + } else { + /* + * Got some other unrecognized signature. + */ + printf("%-*s ", VCOL, "Signature:"); + for (i = 0; i < 8; i++) { + if (sig[i] > ' ' && sig[i] <= '~' && '\\' != sig[i]) { + HDputchar(sig[i]); + } else if ('\\' == sig[i]) { + HDputchar('\\'); + HDputchar('\\'); + } else { + printf("\\%03o", sig[i]); + } + } + HDputchar('\n'); + + fprintf(stderr, "unknown signature\n"); + HDexit(4); + } + + if (status < 0) { + fprintf(stderr, "An error occurred\n"); + HDexit(5); + } + H5Fclose(fid); + return 0; +} diff --git a/tools/h5import.c b/tools/h5import.c new file mode 100644 index 0000000..de1af53 --- /dev/null +++ b/tools/h5import.c @@ -0,0 +1,119 @@ +/* + * Copyright (C) 1998 NCSA + * All rights reserved. + * + * Programmer: Robb Matzke <matzke@llnl.gov> + * Thursday, June 11, 1998 + * + * Purpose: Create an hdf5 file with a 1d dataset of uint8. + */ +#include <fcntl.h> +#include <hdf5.h> +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/stat.h> + + +/*------------------------------------------------------------------------- + * Function: usage + * + * Purpose: Print a usage message and exit with non-zero status + * + * Return: never returns + * + * Programmer: Robb Matzke + * Thursday, June 11, 1998 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static void +usage (const char *argv0) +{ + fprintf (stderr, "Usage: %s -f HDF5-FILE FILES...\n", argv0); + exit (1); +} + + +/*------------------------------------------------------------------------- + * Function: main + * + * Purpose: + * + * Return: Success: 0 + * + * Failure: 1 + * + * Programmer: Robb Matzke + * Thursday, June 11, 1998 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +int +main (int argc, char *argv[]) +{ + hid_t file, space, dset; + const char *output_name, *dset_name; + int argno, fd=-1; + hsize_t size[1]; + struct stat sb; + + /* Parse arguments */ + if (argc<4) usage (argv[0]); + if (strcmp (argv[1], "-f")) usage (argv[0]); + output_name = argv[2]; + + /* create the file */ + H5E_BEGIN_TRY { + if ((file = H5Fcreate (output_name, H5F_ACC_EXCL, + H5P_DEFAULT, H5P_DEFAULT))<0 && + (file = H5Fopen (output_name, H5F_ACC_RDWR, H5P_DEFAULT)<0)) { + fprintf (stderr, "%s: unable to create or open hdf5 file\n", + output_name); + exit (1); + } + } H5E_END_TRY; + + /* process files from command-line */ + for (argno=3; argno<argc; argno++) { + + /* Open the file */ + if ((dset_name=strrchr (argv[argno], '/'))) dset_name++; + else dset_name = argv[argno]; + fprintf (stderr, "%s\n", dset_name); + if ((fd=open (argv[argno], O_RDONLY))<0) { + perror (argv[argno]); + goto next; + } + if (fstat (fd, &sb)<0) { + perror (argv[argno]); + goto next; + } + + /* Data space */ + size[0] = sb.st_size; + if ((space = H5Screate_simple (1, size, size))<0) goto next; + + /* Dataset */ + if ((dset=H5Dcreate (file, dset_name, H5T_NATIVE_CHAR, + space, H5P_DEFAULT))<0) goto next; + + + + next: + if (fd>=0) close (fd); + fd = -1; + H5E_BEGIN_TRY { + H5Sclose (space); + H5Dclose (dset); + } H5E_END_TRY; + } + + /* Close the file */ + H5Fclose (file); + return 0; +} diff --git a/tools/h5ls.c b/tools/h5ls.c new file mode 100644 index 0000000..4b0ea75 --- /dev/null +++ b/tools/h5ls.c @@ -0,0 +1,197 @@ +/* + * Copyright (C) 1998 NCSA + * All rights reserved. + * + * Programmer: Robb Matzke <matzke@llnl.gov> + * Monday, March 23, 1998 + */ +#include <hdf5.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <H5private.h> +#ifndef HAVE_ATTRIBUTE +# undef __attribute__ +# define __attribute__(X) /*void*/ +# define __unused__ /*void*/ +#else +# define __unused__ __attribute__((unused)) +#endif + +static void +usage (const char *progname) +{ + fprintf (stderr, "usage: %s FILE [GROUP]\n", progname); + fprintf (stderr, " The file name may contain a printf integer format " + "to open a file family.\n"); + exit (1); +} + + +/*------------------------------------------------------------------------- + * Function: list_attr + * + * Purpose: Prints information about attributes. + * + * Return: Success: 0 + * + * Failure: -1 + * + * Programmer: Robb Matzke + * Friday, June 5, 1998 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static herr_t +list_attr (hid_t obj, const char *attr_name, void __unused__ *op_data) +{ + hid_t attr; + int i; + + printf ("%*s%s", 26, "", attr_name); + if ((attr = H5Aopen_name (obj, attr_name))) { + hid_t space = H5Aget_space (attr); + hsize_t size[64]; + int ndims = H5Sget_dims (space, size, NULL); + H5Sclose (space); + printf (" {"); + for (i=0; i<ndims; i++) { + HDfprintf (stdout, "%s%Hu", i?", ":"", size[i]); + } + putchar ('}'); + H5Aclose (attr); + } + + putchar ('\n'); + return 0; +} + + +/*------------------------------------------------------------------------- + * Function: list + * + * Purpose: Prints the group member name. + * + * Return: Success: 0 + * + * Failure: -1 + * + * Programmer: Robb Matzke + * Monday, March 23, 1998 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static herr_t +list (hid_t group, const char *name, void __unused__ *op_data) +{ + hid_t obj; + hid_t (*func)(void*); + void *edata; + int i; + char buf[512]; + H5G_stat_t statbuf; + + /* Disable error reporting */ + H5Eget_auto (&func, &edata); + H5Eset_auto (NULL, NULL); + + /* Print info about each name */ + printf ("%-25s ", name); + + if (H5Gstat (group, name, TRUE, &statbuf)>=0) { + sprintf (buf, "%lu:%lu:%lu:%lu", + statbuf.fileno[1], statbuf.fileno[0], + statbuf.objno[1], statbuf.objno[0]); + printf ("%-20s ", buf); + } + + if ((obj=H5Dopen (group, name))>=0) { + hsize_t size[64]; + hsize_t maxsize[64]; + hid_t space = H5Dget_space (obj); + int ndims = H5Sget_dims(space, size, maxsize); + printf ("Dataset {"); + for (i=0; i<ndims; i++) { + HDfprintf (stdout, "%s%Hu", i?", ":"", size[i]); + if (maxsize[i]==H5S_UNLIMITED) + HDfprintf (stdout, "/%s", "Inf"); + else + HDfprintf (stdout, "/%Hu", maxsize[i]); + } + printf ("}\n"); + H5Dclose (space); + H5Aiterate (obj, NULL, list_attr, NULL); + H5Dclose (obj); + } else if ((obj=H5Gopen (group, name))>=0) { + printf ("Group\n"); + H5Aiterate (obj, NULL, list_attr, NULL); + H5Gclose (obj); + } else if (H5Gget_linkval (group, name, sizeof(buf), buf)>=0) { + if (NULL==HDmemchr (buf, 0, sizeof(buf))) { + strcpy (buf+sizeof(buf)-4, "..."); + } + printf (" -> %s\n", buf); + } else if ((obj=H5Topen (group, name))>=0) { + printf ("Data type\n"); + H5Aiterate (obj, NULL, list_attr, NULL); + H5Tclose (obj); + } else { + printf ("Unknown Type\n"); + } + + /* Restore error reporting */ + H5Eset_auto (func, edata); + return 0; +} + + + +/*------------------------------------------------------------------------- + * Function: main + * + * Purpose: Opens a file and lists the specified group + * + * Return: Success: 0 + * + * Failure: 1 + * + * Programmer: Robb Matzke + * Monday, March 23, 1998 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +int +main (int argc, char *argv[]) +{ + hid_t file, plist=H5P_DEFAULT; + const char *fname = NULL; + const char *gname = "/"; + const char *progname; + + /* Arguments */ + if ((progname=strrchr (argv[0], '/'))) progname++; + else progname = argv[0]; + if (argc<2 || argc>3) usage (progname); + fname = argv[1]; + if (argc>=3) gname = argv[2]; + + /* + * Open the file. If the file name contains a `%' then assume that a + * file family is being opened. + */ + if (strchr (fname, '%')) { + plist = H5Pcreate (H5P_FILE_ACCESS); + H5Pset_family (plist, 0, H5P_DEFAULT); + } + if ((file = H5Fopen (fname, H5F_ACC_RDONLY, plist))<0) exit (1); + if (H5Giterate (file, gname, NULL, list, NULL)<0) exit (1); + if (H5Fclose (file)<0) exit (1); + return 0; +} diff --git a/tools/h5repart.c b/tools/h5repart.c new file mode 100644 index 0000000..8faa9ea --- /dev/null +++ b/tools/h5repart.c @@ -0,0 +1,388 @@ +/* + * Copyright (C) 1998 NCSA + * All rights reserved. + * + * Programmer: Robb Matzke <matzke@llnl.gov> + * Wednesday, May 13, 1998 + * + * Purpose: Repartitions a file family. This program can be used to + * split a single file into a family of files, join a family of + * files into a single file, or copy one family to another while + * changing the size of the family members. It can also be used + * to copy a single file to a single file with holes. + */ +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <hdf5.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <unistd.h> + +#define FALSE 0 +#define TRUE 1 +#define NAMELEN 4096 +#define GB *1024*1024*1024 + +#define MIN(X,Y) ((X)<(Y)?(X):(Y)) +#define MIN3(X,Y,Z) MIN(MIN(X,Y),Z) + + +/*------------------------------------------------------------------------- + * Function: usage + * + * Purpose: Prints a usage message. + * + * Return: void + * + * Programmer: Robb Matzke + * Wednesday, May 13, 1998 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static void +usage (const char *progname) +{ + fprintf (stderr, "usage: %s [-[b|m] N[g|m|k]] SRC DST\n", progname); + fprintf (stderr, " -b N The I/O block size, defaults to 1kB\n"); + fprintf (stderr, " -m N The destination member size or 1GB\n"); + fprintf (stderr, " SRC The name of the source file\n"); + fprintf (stderr, " DST The name of the destination files\n"); + fprintf (stderr, "Sizes may be suffixed with `g' for GB, `m' for MB or " + "`k' for kB.\n"); + fprintf (stderr, "File family names include an integer printf " + "format such as `%%d'\n"); + exit (1); +} + + +/*------------------------------------------------------------------------- + * Function: get_size + * + * Purpose: Reads a size option of the form `-XNS' where `X' is any + * letter, `N' is a multi-character positive decimal number, and + * `S' is an optional suffix letter in the set [GgMmk]. The + * option may also be split among two arguments as: `-X NS'. + * The input value of ARGNO is the argument number for the + * switch in the ARGV vector and ARGC is the number of entries + * in that vector. + * + * Return: Success: The value N multiplied according to the + * suffix S. On return ARGNO will be the number + * of the next argument to process. + * + * Failure: Calls usage() which exits with a non-zero + * status. + * + * Programmer: Robb Matzke + * Wednesday, May 13, 1998 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static off_t +get_size (const char *progname, int *argno, int argc, char *argv[]) +{ + off_t retval; + char *suffix; + + if (isdigit (argv[*argno][2])) { + retval = strtol (argv[*argno]+2, &suffix, 10); + (*argno)++; + } else if (argv[*argno][2] || *argno+1>=argc) { + usage (progname); + } else { + retval = strtol (argv[*argno+1], &suffix, 0); + if (suffix==argv[*argno+1]) usage (progname); + *argno += 2; + } + if (suffix && suffix[0] && !suffix[1]) { + switch (*suffix) { + case 'G': + case 'g': + retval *= 1024 * 1024 * 1024; + break; + case 'M': + case 'm': + retval *= 1024 * 1024; + break; + case 'k': + retval *= 1024; + break; + default: + usage (progname); + } + } else if (suffix && suffix[0]) { + usage (progname); + } + return retval; +} + + +/*------------------------------------------------------------------------- + * Function: main + * + * Purpose: Split an hdf5 file + * + * Return: Success: + * + * Failure: + * + * Programmer: Robb Matzke + * Wednesday, May 13, 1998 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +int +main (int argc, char *argv[]) +{ + const char *prog_name; /*program name */ + size_t blk_size=1024; /*size of each I/O block */ + char *buf=NULL; /*I/O block buffer */ + size_t n, i; /*counters */ + ssize_t nio; /*I/O return value */ + int argno=1; /*program argument number */ + int src, dst=-1; /*source & destination files */ + int need_seek=FALSE; /*destination needs to seek? */ + int need_write; /*data needs to be written? */ + struct stat sb; /*temporary file stat buffer */ + int verbose=FALSE; /*display file names? */ + size_t left_overs=0; /*amount of zeros left over */ + + const char *src_gen_name; /*general source name */ + char src_name[NAMELEN]; /*source member name */ + off_t src_offset=0; /*offset in source member */ + int src_is_family; /*is source name a family name? */ + int src_membno=0; /*source member number */ + off_t src_size; /*source logical member size */ + off_t src_act_size; /*source actual member size */ + + const char *dst_gen_name; /*general destination name */ + char dst_name[NAMELEN]; /*destination member name */ + off_t dst_offset=0; /*offset in destination member */ + int dst_is_family; /*is dst name a family name? */ + int dst_membno=0; /*destination member number */ + off_t dst_size=1 GB; /*destination logical memb size */ + + /* + * Get the program name from argv[0]. Use only the last component. + */ + if ((prog_name=strrchr (argv[0], '/'))) prog_name++; + else prog_name = argv[0]; + + /* + * Parse switches. + */ + while (argno<argc && '-'==argv[argno][0]) { + if (!strcmp (argv[argno], "-v")) { + verbose = TRUE; + argno++; + } else if ('b'==argv[argno][1]) { + blk_size = get_size (prog_name, &argno, argc, argv); + } else if ('m'==argv[argno][1]) { + dst_size = get_size (prog_name, &argno, argc, argv); + } else { + usage (prog_name); + } + } + + /* + * Get the name for the source file and open the first member. The size + * of the first member determines the logical size of all the members. + */ + if (argno>=argc) usage (prog_name); + src_gen_name = argv[argno++]; + sprintf (src_name, src_gen_name, src_membno); + src_is_family = strcmp (src_name, src_gen_name); + if ((src=open (src_name, O_RDONLY))<0) { + perror (src_name); + exit (1); + } + if (fstat (src, &sb)<0) { + perror ("fstat"); + exit (1); + } + src_size = src_act_size = sb.st_size; + if (verbose) fprintf (stderr, "< %s\n", src_name); + + /* + * Get the name for the destination file and open the first member. + */ + if (argno>=argc) usage (prog_name); + dst_gen_name = argv[argno++]; + sprintf (dst_name, dst_gen_name, dst_membno); + dst_is_family = strcmp (dst_name, dst_gen_name); + if ((dst=open (dst_name, O_RDWR|O_CREAT|O_TRUNC, 0666))<0) { + perror (dst_name); + exit (1); + } + if (verbose) fprintf (stderr, "> %s\n", dst_name); + + /* No more arguments */ + if (argno<argc) usage (prog_name); + + /* Now the real work, split the file */ + buf = malloc (blk_size); + while (src_offset<src_size) { + + /* Read a block. The amount to read is the minimum of: + * 1. The I/O block size + * 2. What's left to write in the destination member + * 3. Left over zeros or what's left in the source member. + */ + n = blk_size; + if (dst_is_family) n = (size_t)MIN((off_t)n, dst_size-dst_offset); + if (left_overs) { + n = MIN (n, left_overs); + left_overs -= n; + need_write = FALSE; + } else if (src_offset<src_act_size) { + n = (size_t)MIN ((off_t)n, src_act_size-src_offset); + if ((nio=read (src, buf, n))<0) { + perror ("read"); + exit (1); + } else if ((size_t)nio!=n) { + fprintf (stderr, "%s: short read\n", src_name); + exit (1); + } + for (i=0; i<n; i++) { + if (buf[i]) break; + } + need_write = (i<n); + } else { + n = 0; + left_overs = src_size - src_act_size; + need_write = FALSE; + } + + /* + * If the block contains non-zero data then write it to the + * destination, otherwise just remember that we'll have to do a seek + * later in the destination when we finally get non-zero data. + */ + if (need_write) { + if (need_seek && lseek (dst, dst_offset, SEEK_SET)<0) { + perror ("lseek"); + exit (1); + } + if ((nio=write (dst, buf, n))<0) { + perror ("write"); + exit (1); + } else if ((size_t)nio!=n) { + fprintf (stderr, "%s: short write\n", dst_name); + exit (1); + } + need_seek = FALSE; + } else { + need_seek = TRUE; + } + + /* + * Update the source offset and open the next source family member if + * necessary. The source stream ends at the first member which + * cannot be opened because it doesn't exist. At the end of the + * source stream, update the destination offset and break out of the + * loop. The destination offset must be updated so we can fix + * trailing holes. + */ + src_offset += n; + if (src_offset==src_act_size) { + close (src); + if (!src_is_family) { + dst_offset += n; + break; + } + sprintf (src_name, src_gen_name, ++src_membno); + if ((src=open (src_name, O_RDONLY))<0 && ENOENT==errno) { + dst_offset += n; + break; + } else if (src<0) { + perror (src_name); + exit (1); + } + if (fstat (src, &sb)<0) { + perror ("fstat"); + exit (1); + } + src_act_size = sb.st_size; + if (src_act_size>src_size) { + fprintf (stderr, "%s: member truncated to %lu bytes\n", + src_name, (unsigned long)src_size); + } + src_offset = 0; + if (verbose) fprintf (stderr, "< %s\n", src_name); + } + + /* + * Update the destination offset, opening a new member if one will be + * needed. The first member is extended to the logical member size + * but other members might be smaller if they end with a hole. + */ + dst_offset += n; + if (dst_is_family && dst_offset==dst_size) { + if (0==dst_membno) { + if (lseek (dst, dst_size-1, SEEK_SET)<0) { + perror ("lseek"); + exit (1); + } + if (read (dst, buf, 1)<0) { + perror ("read"); + exit (1); + } + if (lseek (dst, dst_size-1, SEEK_SET)<0) { + perror ("lseek"); + exit (1); + } + if (write (dst, buf, 1)<0) { + perror ("write"); + exit (1); + } + } + close (dst); + sprintf (dst_name, dst_gen_name, ++dst_membno); + if ((dst=open (dst_name, O_RDWR|O_CREAT|O_TRUNC, 0666))<0) { + perror (dst_name); + exit (1); + } + dst_offset = 0; + need_seek = FALSE; + if (verbose) fprintf (stderr, "> %s\n", dst_name); + } + } + + /* + * Make sure the last family member is the right size and then close it. + * The last member can't end with a hole or hdf5 will think that the + * family has been truncated. + */ + if (need_seek) { + if (lseek (dst, dst_offset-1, SEEK_SET)<0) { + perror ("lseek"); + exit (1); + } + if (read (dst, buf, 1)<0) { + perror ("read"); + exit (1); + } + if (lseek (dst, dst_offset-1, SEEK_SET)<0) { + perror ("lseek"); + exit (1); + } + if (write (dst, buf, 1)<0) { + perror ("write"); + exit (1); + } + } + close (dst); + + /* Free resources and return */ + free (buf); + return 0; +} |