xref: /petsc/src/sys/fileio/sysio.c (revision c4762a1b19cd2af06abeed90e8f9d34fb975dd94)
1 
2 /*
3    This file contains simple binary read/write routines.
4  */
5 
6 #include <petscsys.h>
7 #include <errno.h>
8 #include <fcntl.h>
9 #if defined(PETSC_HAVE_UNISTD_H)
10 #include <unistd.h>
11 #endif
12 #if defined(PETSC_HAVE_IO_H)
13 #include <io.h>
14 #endif
15 #include <petscbt.h>
16 
17 const char *const PetscFileModes[] = {"READ","WRITE","APPEND","UPDATE","APPEND_UPDATE","PetscFileMode","PETSC_FILE_",NULL};
18 
19 /* --------------------------------------------------------- */
20 /*
21   PetscByteSwapEnum - Swap bytes in a  PETSc Enum
22 
23 */
24 PetscErrorCode  PetscByteSwapEnum(PetscEnum *buff,PetscInt n)
25 {
26   PetscInt  i,j;
27   PetscEnum tmp = ENUM_DUMMY;
28   char      *ptr1,*ptr2 = (char*)&tmp;
29 
30   PetscFunctionBegin;
31   for (j=0; j<n; j++) {
32     ptr1 = (char*)(buff + j);
33     for (i=0; i<(PetscInt)sizeof(PetscEnum); i++) ptr2[i] = ptr1[sizeof(PetscEnum)-1-i];
34     for (i=0; i<(PetscInt)sizeof(PetscEnum); i++) ptr1[i] = ptr2[i];
35   }
36   PetscFunctionReturn(0);
37 }
38 
39 /*
40   PetscByteSwapBool - Swap bytes in a  PETSc Bool
41 
42 */
43 PetscErrorCode  PetscByteSwapBool(PetscBool *buff,PetscInt n)
44 {
45   PetscInt  i,j;
46   PetscBool tmp = PETSC_FALSE;
47   char      *ptr1,*ptr2 = (char*)&tmp;
48 
49   PetscFunctionBegin;
50   for (j=0; j<n; j++) {
51     ptr1 = (char*)(buff + j);
52     for (i=0; i<(PetscInt)sizeof(PetscBool); i++) ptr2[i] = ptr1[sizeof(PetscBool)-1-i];
53     for (i=0; i<(PetscInt)sizeof(PetscBool); i++) ptr1[i] = ptr2[i];
54   }
55   PetscFunctionReturn(0);
56 }
57 
58 /*
59   PetscByteSwapInt - Swap bytes in a  PETSc integer (which may be 32 or 64 bits)
60 
61 */
62 PetscErrorCode  PetscByteSwapInt(PetscInt *buff,PetscInt n)
63 {
64   PetscInt i,j,tmp = 0;
65   char     *ptr1,*ptr2 = (char*)&tmp;
66 
67   PetscFunctionBegin;
68   for (j=0; j<n; j++) {
69     ptr1 = (char*)(buff + j);
70     for (i=0; i<(PetscInt)sizeof(PetscInt); i++) ptr2[i] = ptr1[sizeof(PetscInt)-1-i];
71     for (i=0; i<(PetscInt)sizeof(PetscInt); i++) ptr1[i] = ptr2[i];
72   }
73   PetscFunctionReturn(0);
74 }
75 
76 /*
77   PetscByteSwapInt64 - Swap bytes in a  PETSc integer (64 bits)
78 
79 */
80 PetscErrorCode  PetscByteSwapInt64(PetscInt64 *buff,PetscInt n)
81 {
82   PetscInt   i,j;
83   PetscInt64 tmp = 0;
84   char       *ptr1,*ptr2 = (char*)&tmp;
85 
86   PetscFunctionBegin;
87   for (j=0; j<n; j++) {
88     ptr1 = (char*)(buff + j);
89     for (i=0; i<(PetscInt)sizeof(PetscInt64); i++) ptr2[i] = ptr1[sizeof(PetscInt64)-1-i];
90     for (i=0; i<(PetscInt)sizeof(PetscInt64); i++) ptr1[i] = ptr2[i];
91   }
92   PetscFunctionReturn(0);
93 }
94 
95 /* --------------------------------------------------------- */
96 /*
97   PetscByteSwapShort - Swap bytes in a short
98 */
99 PetscErrorCode  PetscByteSwapShort(short *buff,PetscInt n)
100 {
101   PetscInt i,j;
102   short    tmp;
103   char     *ptr1,*ptr2 = (char*)&tmp;
104 
105   PetscFunctionBegin;
106   for (j=0; j<n; j++) {
107     ptr1 = (char*)(buff + j);
108     for (i=0; i<(PetscInt) sizeof(short); i++) ptr2[i] = ptr1[sizeof(short)-1-i];
109     for (i=0; i<(PetscInt) sizeof(short); i++) ptr1[i] = ptr2[i];
110   }
111   PetscFunctionReturn(0);
112 }
113 /*
114   PetscByteSwapLong - Swap bytes in a long
115 */
116 PetscErrorCode  PetscByteSwapLong(long *buff,PetscInt n)
117 {
118   PetscInt i,j;
119   long     tmp;
120   char     *ptr1,*ptr2 = (char*)&tmp;
121 
122   PetscFunctionBegin;
123   for (j=0; j<n; j++) {
124     ptr1 = (char*)(buff + j);
125     for (i=0; i<(PetscInt) sizeof(long); i++) ptr2[i] = ptr1[sizeof(long)-1-i];
126     for (i=0; i<(PetscInt) sizeof(long); i++) ptr1[i] = ptr2[i];
127   }
128   PetscFunctionReturn(0);
129 }
130 /* --------------------------------------------------------- */
131 /*
132   PetscByteSwapReal - Swap bytes in a PetscReal
133 */
134 PetscErrorCode  PetscByteSwapReal(PetscReal *buff,PetscInt n)
135 {
136   PetscInt  i,j;
137   PetscReal tmp,*buff1 = (PetscReal*)buff;
138   char      *ptr1,*ptr2 = (char*)&tmp;
139 
140   PetscFunctionBegin;
141   for (j=0; j<n; j++) {
142     ptr1 = (char*)(buff1 + j);
143     for (i=0; i<(PetscInt) sizeof(PetscReal); i++) ptr2[i] = ptr1[sizeof(PetscReal)-1-i];
144     for (i=0; i<(PetscInt) sizeof(PetscReal); i++) ptr1[i] = ptr2[i];
145   }
146   PetscFunctionReturn(0);
147 }
148 /* --------------------------------------------------------- */
149 /*
150   PetscByteSwapScalar - Swap bytes in a PetscScalar
151   The complex case is dealt with with an array of PetscReal, twice as long.
152 */
153 PetscErrorCode  PetscByteSwapScalar(PetscScalar *buff,PetscInt n)
154 {
155   PetscInt  i,j;
156   PetscReal tmp,*buff1 = (PetscReal*)buff;
157   char      *ptr1,*ptr2 = (char*)&tmp;
158 
159   PetscFunctionBegin;
160 #if defined(PETSC_USE_COMPLEX)
161   n *= 2;
162 #endif
163   for (j=0; j<n; j++) {
164     ptr1 = (char*)(buff1 + j);
165     for (i=0; i<(PetscInt) sizeof(PetscReal); i++) ptr2[i] = ptr1[sizeof(PetscReal)-1-i];
166     for (i=0; i<(PetscInt) sizeof(PetscReal); i++) ptr1[i] = ptr2[i];
167   }
168   PetscFunctionReturn(0);
169 }
170 /* --------------------------------------------------------- */
171 /*
172   PetscByteSwapDouble - Swap bytes in a double
173 */
174 PetscErrorCode  PetscByteSwapDouble(double *buff,PetscInt n)
175 {
176   PetscInt i,j;
177   double   tmp,*buff1 = (double*)buff;
178   char     *ptr1,*ptr2 = (char*)&tmp;
179 
180   PetscFunctionBegin;
181   for (j=0; j<n; j++) {
182     ptr1 = (char*)(buff1 + j);
183     for (i=0; i<(PetscInt) sizeof(double); i++) ptr2[i] = ptr1[sizeof(double)-1-i];
184     for (i=0; i<(PetscInt) sizeof(double); i++) ptr1[i] = ptr2[i];
185   }
186   PetscFunctionReturn(0);
187 }
188 
189 /*
190   PetscByteSwapFloat - Swap bytes in a float
191 */
192 PetscErrorCode PetscByteSwapFloat(float *buff,PetscInt n)
193 {
194   PetscInt i,j;
195   float    tmp,*buff1 = (float*)buff;
196   char     *ptr1,*ptr2 = (char*)&tmp;
197 
198   PetscFunctionBegin;
199   for (j=0; j<n; j++) {
200     ptr1 = (char*)(buff1 + j);
201     for (i=0; i<(PetscInt) sizeof(float); i++) ptr2[i] = ptr1[sizeof(float)-1-i];
202     for (i=0; i<(PetscInt) sizeof(float); i++) ptr1[i] = ptr2[i];
203   }
204   PetscFunctionReturn(0);
205 }
206 
207 PetscErrorCode PetscByteSwap(void *data,PetscDataType pdtype,PetscInt count)
208 {
209   PetscErrorCode ierr;
210 
211   PetscFunctionBegin;
212   if      (pdtype == PETSC_INT)    {ierr = PetscByteSwapInt((PetscInt*)data,count);CHKERRQ(ierr);}
213   else if (pdtype == PETSC_ENUM)   {ierr = PetscByteSwapEnum((PetscEnum*)data,count);CHKERRQ(ierr);}
214   else if (pdtype == PETSC_BOOL)   {ierr = PetscByteSwapBool((PetscBool*)data,count);CHKERRQ(ierr);}
215   else if (pdtype == PETSC_SCALAR) {ierr = PetscByteSwapScalar((PetscScalar*)data,count);CHKERRQ(ierr);}
216   else if (pdtype == PETSC_REAL)   {ierr = PetscByteSwapReal((PetscReal*)data,count);CHKERRQ(ierr);}
217   else if (pdtype == PETSC_COMPLEX){ierr = PetscByteSwapReal((PetscReal*)data,2*count);CHKERRQ(ierr);}
218   else if (pdtype == PETSC_INT64)  {ierr = PetscByteSwapInt64((PetscInt64*)data,count);CHKERRQ(ierr);}
219   else if (pdtype == PETSC_DOUBLE) {ierr = PetscByteSwapDouble((double*)data,count);CHKERRQ(ierr);}
220   else if (pdtype == PETSC_FLOAT)  {ierr = PetscByteSwapFloat((float*)data,count);CHKERRQ(ierr);}
221   else if (pdtype == PETSC_SHORT)  {ierr = PetscByteSwapShort((short*)data,count);CHKERRQ(ierr);}
222   else if (pdtype == PETSC_LONG)   {ierr = PetscByteSwapLong((long*)data,count);CHKERRQ(ierr);}
223   PetscFunctionReturn(0);
224 }
225 
226 /*@C
227    PetscBinaryRead - Reads from a binary file.
228 
229    Not Collective
230 
231    Input Parameters:
232 +  fd - the file descriptor
233 .  num  - the maximum number of items to read
234 -  type - the type of items to read (PETSC_INT, PETSC_REAL, PETSC_SCALAR, etc.)
235 
236    Output Parameters:
237 +  data - the buffer
238 -  count - the number of items read, optional
239 
240    Level: developer
241 
242    Notes:
243    If count is not provided and the number of items read is less than
244    the maximum number of items to read, then this routine errors.
245 
246    PetscBinaryRead() uses byte swapping to work on all machines; the files
247    are written to file ALWAYS using big-endian ordering. On little-endian machines the numbers
248    are converted to the little-endian format when they are read in from the file.
249    When PETSc is ./configure with --with-64-bit-indices the integers are written to the
250    file as 64 bit integers, this means they can only be read back in when the option --with-64-bit-indices
251    is used.
252 
253 .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscViewerBinaryGetDescriptor(), PetscBinarySynchronizedWrite(),
254           PetscBinarySynchronizedRead(), PetscBinarySynchronizedSeek()
255 @*/
256 PetscErrorCode  PetscBinaryRead(int fd,void *data,PetscInt num,PetscInt *count,PetscDataType type)
257 {
258   size_t            typesize, m = (size_t) num, n = 0, maxblock = 65536;
259   char              *p = (char*)data;
260 #if defined(PETSC_USE_REAL___FLOAT128)
261   PetscBool         readdouble = PETSC_FALSE;
262   double            *pdouble;
263 #endif
264   void              *ptmp = data;
265   char              *fname = NULL;
266   PetscErrorCode    ierr;
267 
268   PetscFunctionBegin;
269   if (count) *count = 0;
270   if (num < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Trying to read a negative amount of data %D",num);
271   if (!num) PetscFunctionReturn(0);
272 
273   if (type == PETSC_FUNCTION) {
274     m     = 64;
275     type  = PETSC_CHAR;
276     fname = (char*)malloc(m*sizeof(char));
277     p     = (char*)fname;
278     ptmp  = (void*)fname;
279     if (!fname) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Cannot allocate space for function name");
280   }
281   if (type == PETSC_BIT_LOGICAL) m = PetscBTLength(m);
282 
283   ierr = PetscDataTypeGetSize(type,&typesize);CHKERRQ(ierr);
284 
285 #if defined(PETSC_USE_REAL___FLOAT128)
286   ierr = PetscOptionsGetBool(NULL,NULL,"-binary_read_double",&readdouble,NULL);CHKERRQ(ierr);
287   /* If using __float128 precision we still read in doubles from file */
288   if ((type == PETSC_REAL || type == PETSC_COMPLEX) && readdouble) {
289     PetscInt cnt = num * ((type == PETSC_REAL) ? 1 : 2);
290     ierr = PetscMalloc1(cnt,&pdouble);CHKERRQ(ierr);
291     p = (char*)pdouble;
292     typesize /= 2;
293   }
294 #endif
295 
296   m *= typesize;
297 
298   while (m) {
299     size_t len = (m < maxblock) ? m : maxblock;
300     int    ret = (int)read(fd,p,len);
301     if (ret < 0 && errno == EINTR) continue;
302     if (!ret && len > 0) break; /* Proxy for EOF */
303     if (ret < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_READ,"Error reading from file, errno %d",errno);
304     m -= ret;
305     p += ret;
306     n += ret;
307   }
308   if (m && !count) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_READ,"Read past end of file");
309 
310   num = (PetscInt)(n/typesize); /* Should we require `n % typesize == 0` ? */
311   if (count) *count = num;      /* TODO: This is most likely wrong for PETSC_BIT_LOGICAL */
312 
313 #if defined(PETSC_USE_REAL___FLOAT128)
314   if ((type == PETSC_REAL || type == PETSC_COMPLEX) && readdouble) {
315     PetscInt  i, cnt = num * ((type == PETSC_REAL) ? 1 : 2);
316     PetscReal *preal = (PetscReal*)data;
317     if (!PetscBinaryBigEndian()) {ierr = PetscByteSwapDouble(pdouble,cnt);CHKERRQ(ierr);}
318     for (i=0; i<cnt; i++) preal[i] = pdouble[i];
319     ierr = PetscFree(pdouble);CHKERRQ(ierr);
320     PetscFunctionReturn(0);
321   }
322 #endif
323 
324   if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(ptmp,type,num);CHKERRQ(ierr);}
325 
326   if (type == PETSC_FUNCTION) {
327 #if defined(PETSC_SERIALIZE_FUNCTIONS)
328     ierr = PetscDLSym(NULL,fname,(void**)data);CHKERRQ(ierr);
329 #else
330     *(void**)data = NULL;
331 #endif
332     free(fname);
333   }
334   PetscFunctionReturn(0);
335 }
336 
337 /*@C
338    PetscBinaryWrite - Writes to a binary file.
339 
340    Not Collective
341 
342    Input Parameters:
343 +  fd     - the file
344 .  p      - the buffer
345 .  n      - the number of items to write
346 -  type   - the type of items to read (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)
347 
348    Level: advanced
349 
350    Notes:
351    PetscBinaryWrite() uses byte swapping to work on all machines; the files
352    are written using big-endian ordering to the file. On little-endian machines the numbers
353    are converted to the big-endian format when they are written to disk.
354    When PETSc is ./configure with --with-64-bit-indices the integers are written to the
355    file as 64 bit integers, this means they can only be read back in when the option --with-64-bit-indices
356    is used.
357 
358    If running with __float128 precision the output is in __float128 unless one uses the -binary_write_double option
359 
360    The Buffer p should be read-write buffer, and not static data.
361    This way, byte-swapping is done in-place, and then the buffer is
362    written to the file.
363 
364    This routine restores the original contents of the buffer, after
365    it is written to the file. This is done by byte-swapping in-place
366    the second time.
367 
368    Because byte-swapping may be done on the values in data it cannot be declared const
369 
370 
371 .seealso: PetscBinaryRead(), PetscBinaryOpen(), PetscBinaryClose(), PetscViewerBinaryGetDescriptor(), PetscBinarySynchronizedWrite(),
372           PetscBinarySynchronizedRead(), PetscBinarySynchronizedSeek()
373 @*/
374 PetscErrorCode  PetscBinaryWrite(int fd,const void *p,PetscInt n,PetscDataType type)
375 {
376   const char     *pp = (char*)p;
377   int            err,wsize;
378   size_t         m = (size_t)n,maxblock=65536;
379   PetscErrorCode ierr;
380   const void     *ptmp = p;
381   char           *fname = NULL;
382 #if defined(PETSC_USE_REAL___FLOAT128)
383   PetscBool      writedouble = PETSC_FALSE;
384   double         *ppp;
385   PetscReal      *pv;
386   PetscInt       i;
387 #endif
388   PetscDataType  wtype = type;
389 
390   PetscFunctionBegin;
391   if (n < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Trying to write a negative amount of data %D",n);
392   if (!n) PetscFunctionReturn(0);
393 
394   if (type == PETSC_FUNCTION) {
395 #if defined(PETSC_SERIALIZE_FUNCTIONS)
396     const char *fnametmp;
397 #endif
398     m     = 64;
399     fname = (char*)malloc(m*sizeof(char));
400     if (!fname) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Cannot allocate space for function name");
401 #if defined(PETSC_SERIALIZE_FUNCTIONS)
402     if (n > 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Can only binary view a single function at a time");
403     ierr = PetscFPTFind(*(void**)p,&fnametmp);CHKERRQ(ierr);
404     ierr = PetscStrncpy(fname,fnametmp,m);CHKERRQ(ierr);
405 #else
406     ierr = PetscStrncpy(fname,"",m);CHKERRQ(ierr);
407 #endif
408     wtype = PETSC_CHAR;
409     pp    = (char*)fname;
410     ptmp  = (void*)fname;
411   }
412 
413 #if defined(PETSC_USE_REAL___FLOAT128)
414   ierr = PetscOptionsGetBool(NULL,NULL,"-binary_write_double",&writedouble,NULL);CHKERRQ(ierr);
415   /* If using __float128 precision we still write in doubles to file */
416   if ((type == PETSC_SCALAR || type == PETSC_REAL) && writedouble) {
417     wtype = PETSC_DOUBLE;
418     ierr = PetscMalloc1(n,&ppp);CHKERRQ(ierr);
419     pv = (PetscReal*)pp;
420     for (i=0; i<n; i++) {
421       ppp[i] = (double) pv[i];
422     }
423     pp   = (char*)ppp;
424     ptmp = (char*)ppp;
425   }
426 #endif
427 
428   if (wtype == PETSC_INT)          m *= sizeof(PetscInt);
429   else if (wtype == PETSC_SCALAR)  m *= sizeof(PetscScalar);
430   else if (wtype == PETSC_REAL)    m *= sizeof(PetscReal);
431   else if (wtype == PETSC_DOUBLE)  m *= sizeof(double);
432   else if (wtype == PETSC_FLOAT)   m *= sizeof(float);
433   else if (wtype == PETSC_SHORT)   m *= sizeof(short);
434   else if (wtype == PETSC_LONG)    m *= sizeof(long);
435   else if (wtype == PETSC_CHAR)    m *= sizeof(char);
436   else if (wtype == PETSC_ENUM)    m *= sizeof(PetscEnum);
437   else if (wtype == PETSC_BOOL)    m *= sizeof(PetscBool);
438   else if (wtype == PETSC_INT64)   m *= sizeof(PetscInt64);
439   else if (wtype == PETSC_BIT_LOGICAL) m = PetscBTLength(m)*sizeof(char);
440   else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Unknown type");
441 
442   if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap((void*)ptmp,wtype,n);CHKERRQ(ierr);}
443 
444   while (m) {
445     wsize = (m < maxblock) ? m : maxblock;
446     err   = write(fd,pp,wsize);
447     if (err < 0 && errno == EINTR) continue;
448     if (err != wsize) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_FILE_WRITE,"Error writing to file total size %d err %d wsize %d",(int)n,(int)err,(int)wsize);
449     m  -= wsize;
450     pp += wsize;
451   }
452 
453   if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap((void*)ptmp,wtype,n);CHKERRQ(ierr);}
454 
455   if (type == PETSC_FUNCTION) {
456     free(fname);
457   }
458 #if defined(PETSC_USE_REAL___FLOAT128)
459   if ((type == PETSC_SCALAR || type == PETSC_REAL) && writedouble) {
460     ierr = PetscFree(ppp);CHKERRQ(ierr);
461   }
462 #endif
463   PetscFunctionReturn(0);
464 }
465 
466 /*@C
467    PetscBinaryOpen - Opens a PETSc binary file.
468 
469    Not Collective
470 
471    Input Parameters:
472 +  name - filename
473 -  type - type of binary file, one of FILE_MODE_READ, FILE_MODE_APPEND, FILE_MODE_WRITE
474 
475    Output Parameter:
476 .  fd - the file
477 
478    Level: advanced
479 
480 
481    Notes:
482     Files access with PetscBinaryRead() and PetscBinaryWrite() are ALWAYS written in
483    big-endian format. This means the file can be accessed using PetscBinaryOpen() and
484    PetscBinaryRead() and PetscBinaryWrite() on any machine.
485 
486 .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscFileMode, PetscViewerFileSetMode(), PetscViewerBinaryGetDescriptor(),
487           PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(), PetscBinarySynchronizedSeek()
488 
489 @*/
490 PetscErrorCode  PetscBinaryOpen(const char name[],PetscFileMode mode,int *fd)
491 {
492   PetscFunctionBegin;
493 #if defined(PETSC_HAVE_O_BINARY)
494   if (mode == FILE_MODE_WRITE) {
495     if ((*fd = open(name,O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,0666)) == -1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot create file for writing: %s",name);
496   } else if (mode == FILE_MODE_READ) {
497     if ((*fd = open(name,O_RDONLY|O_BINARY,0)) == -1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot open file for reading: %s",name);
498   } else if (mode == FILE_MODE_APPEND) {
499     if ((*fd = open(name,O_WRONLY|O_BINARY,0)) == -1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot open file for writing: %s",name);
500 #else
501   if (mode == FILE_MODE_WRITE) {
502     if ((*fd = creat(name,0666)) == -1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot create file for writing: %s",name);
503   } else if (mode == FILE_MODE_READ) {
504     if ((*fd = open(name,O_RDONLY,0)) == -1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot open file for reading: %s",name);
505   }
506   else if (mode == FILE_MODE_APPEND) {
507     if ((*fd = open(name,O_WRONLY,0)) == -1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot open file for writing: %s",name);
508 #endif
509   } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Unknown file mode");
510   PetscFunctionReturn(0);
511 }
512 
513 /*@
514    PetscBinaryClose - Closes a PETSc binary file.
515 
516    Not Collective
517 
518    Output Parameter:
519 .  fd - the file
520 
521    Level: advanced
522 
523 .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(),
524           PetscBinarySynchronizedSeek()
525 @*/
526 PetscErrorCode  PetscBinaryClose(int fd)
527 {
528   PetscFunctionBegin;
529   close(fd);
530   PetscFunctionReturn(0);
531 }
532 
533 
534 /*@C
535    PetscBinarySeek - Moves the file pointer on a PETSc binary file.
536 
537    Not Collective
538 
539    Input Parameters:
540 +  fd - the file
541 .  off - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE,
542             etc. in your calculation rather than sizeof() to compute byte lengths.
543 -  whence - if PETSC_BINARY_SEEK_SET then off is an absolute location in the file
544             if PETSC_BINARY_SEEK_CUR then off is an offset from the current location
545             if PETSC_BINARY_SEEK_END then off is an offset from the end of file
546 
547    Output Parameter:
548 .   offset - new offset in file
549 
550    Level: developer
551 
552    Notes:
553    Integers are stored on the file as 32 long, regardless of whether
554    they are stored in the machine as 32 or 64, this means the same
555    binary file may be read on any machine. Hence you CANNOT use sizeof()
556    to determine the offset or location.
557 
558 
559 .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(),
560           PetscBinarySynchronizedSeek()
561 @*/
562 PetscErrorCode  PetscBinarySeek(int fd,off_t off,PetscBinarySeekType whence,off_t *offset)
563 {
564   int iwhence = 0;
565 
566   PetscFunctionBegin;
567   if (whence == PETSC_BINARY_SEEK_SET) iwhence = SEEK_SET;
568   else if (whence == PETSC_BINARY_SEEK_CUR) iwhence = SEEK_CUR;
569   else if (whence == PETSC_BINARY_SEEK_END) iwhence = SEEK_END;
570   else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Unknown seek location");
571 #if defined(PETSC_HAVE_LSEEK)
572   *offset = lseek(fd,off,iwhence);
573 #elif defined(PETSC_HAVE__LSEEK)
574   *offset = _lseek(fd,(long)off,iwhence);
575 #else
576   SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP_SYS,"System does not have a way of seeking on a file");
577 #endif
578   PetscFunctionReturn(0);
579 }
580 
581 /*@C
582    PetscBinarySynchronizedRead - Reads from a binary file.
583 
584    Collective
585 
586    Input Parameters:
587 +  comm - the MPI communicator
588 .  fd - the file descriptor
589 .  num  - the maximum number of items to read
590 -  type - the type of items to read (PETSC_INT, PETSC_REAL, PETSC_SCALAR, etc.)
591 
592    Output Parameters:
593 +  data - the buffer
594 -  count - the number of items read, optional
595 
596    Level: developer
597 
598    Notes:
599    Does a PetscBinaryRead() followed by an MPI_Bcast()
600 
601    If count is not provided and the number of items read is less than
602    the maximum number of items to read, then this routine errors.
603 
604    PetscBinarySynchronizedRead() uses byte swapping to work on all machines.
605    Integers are stored on the file as 32 long, regardless of whether
606    they are stored in the machine as 32 or 64, this means the same
607    binary file may be read on any machine.
608 
609 
610 .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead(), PetscBinarySynchronizedWrite(),
611           PetscBinarySynchronizedSeek()
612 @*/
613 PetscErrorCode  PetscBinarySynchronizedRead(MPI_Comm comm,int fd,void *data,PetscInt num,PetscInt *count,PetscDataType type)
614 {
615   PetscErrorCode ierr;
616   PetscMPIInt    rank;
617   MPI_Datatype   mtype;
618   PetscInt       ibuf[2] = {0, 0};
619   char           *fname = NULL;
620   void           *fptr = NULL;
621 
622   PetscFunctionBegin;
623   if (type == PETSC_FUNCTION) {
624     num   = 64;
625     type  = PETSC_CHAR;
626     fname = (char*)malloc(num*sizeof(char));
627     fptr  = data;
628     data  = (void*)fname;
629     if (!fname) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Cannot allocate space for function name");
630   }
631 
632   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
633   if (!rank) {
634     ibuf[0] = PetscBinaryRead(fd,data,num,count?&ibuf[1]:NULL,type);
635   }
636   ierr = MPI_Bcast(ibuf,2,MPIU_INT,0,comm);CHKERRQ(ierr);
637   ierr = (PetscErrorCode)ibuf[0];CHKERRQ(ierr);
638   ierr = PetscDataTypeToMPIDataType(type,&mtype);CHKERRQ(ierr);
639   ierr = MPI_Bcast(data,count?ibuf[1]:num,mtype,0,comm);CHKERRQ(ierr);
640   if (count) *count = ibuf[1];
641 
642   if (type == PETSC_FUNCTION) {
643 #if defined(PETSC_SERIALIZE_FUNCTIONS)
644     ierr = PetscDLLibrarySym(PETSC_COMM_SELF,&PetscDLLibrariesLoaded,NULL,fname,(void**)fptr);CHKERRQ(ierr);
645 #else
646     *(void**)fptr = NULL;
647 #endif
648     free(fname);
649   }
650   PetscFunctionReturn(0);
651 }
652 
653 /*@C
654    PetscBinarySynchronizedWrite - writes to a binary file.
655 
656    Collective
657 
658    Input Parameters:
659 +  comm - the MPI communicator
660 .  fd - the file
661 .  n  - the number of items to write
662 .  p - the buffer
663 -  type - the type of items to write (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)
664 
665    Level: developer
666 
667    Notes:
668    Process 0 does a PetscBinaryWrite()
669 
670    PetscBinarySynchronizedWrite() uses byte swapping to work on all machines.
671    Integers are stored on the file as 32 long, regardless of whether
672    they are stored in the machine as 32 or 64, this means the same
673    binary file may be read on any machine.
674 
675    Notes:
676     because byte-swapping may be done on the values in data it cannot be declared const
677 
678    WARNING: This is NOT like PetscSynchronizedFPrintf()! This routine ignores calls on all but process 0,
679    while PetscSynchronizedFPrintf() has all processes print their strings in order.
680 
681 
682 .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead(), PetscBinarySynchronizedRead(),
683           PetscBinarySynchronizedSeek()
684 @*/
685 PetscErrorCode  PetscBinarySynchronizedWrite(MPI_Comm comm,int fd,const void *p,PetscInt n,PetscDataType type)
686 {
687   PetscErrorCode ierr;
688   PetscMPIInt    rank;
689 
690   PetscFunctionBegin;
691   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
692   if (!rank) {
693     ierr = PetscBinaryWrite(fd,p,n,type);CHKERRQ(ierr);
694   }
695   PetscFunctionReturn(0);
696 }
697 
698 /*@C
699    PetscBinarySynchronizedSeek - Moves the file pointer on a PETSc binary file.
700 
701 
702    Input Parameters:
703 +  fd - the file
704 .  whence - if PETSC_BINARY_SEEK_SET then size is an absolute location in the file
705             if PETSC_BINARY_SEEK_CUR then size is offset from current location
706             if PETSC_BINARY_SEEK_END then size is offset from end of file
707 -  off    - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE,
708             etc. in your calculation rather than sizeof() to compute byte lengths.
709 
710    Output Parameter:
711 .   offset - new offset in file
712 
713    Level: developer
714 
715    Notes:
716    Integers are stored on the file as 32 long, regardless of whether
717    they are stored in the machine as 32 or 64, this means the same
718    binary file may be read on any machine. Hence you CANNOT use sizeof()
719    to determine the offset or location.
720 
721 
722 .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(),
723           PetscBinarySynchronizedSeek()
724 @*/
725 PetscErrorCode  PetscBinarySynchronizedSeek(MPI_Comm comm,int fd,off_t off,PetscBinarySeekType whence,off_t *offset)
726 {
727   PetscErrorCode ierr;
728   PetscMPIInt    rank;
729 
730   PetscFunctionBegin;
731   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
732   if (!rank) {
733     ierr = PetscBinarySeek(fd,off,whence,offset);CHKERRQ(ierr);
734   }
735   PetscFunctionReturn(0);
736 }
737 
738 #if defined(PETSC_HAVE_MPIIO)
739 
740 #if defined(PETSC_USE_PETSC_MPI_EXTERNAL32)
741 /*
742       MPICH does not provide the external32 representation for MPI_File_set_view() so we need to provide the functions.
743     These are set into MPI in PetscInitialize() via MPI_Register_datarep()
744 
745     Note I use PetscMPIInt for the MPI error codes since that is what MPI uses (instead of the standard PetscErrorCode)
746 
747     The next three routines are not used because MPICH does not support their use
748 
749 */
750 PETSC_EXTERN PetscMPIInt PetscDataRep_extent_fn(MPI_Datatype datatype,MPI_Aint *file_extent,void *extra_state)
751 {
752   MPI_Aint    ub;
753   PetscMPIInt ierr;
754 
755   ierr = MPI_Type_get_extent(datatype,&ub,file_extent);
756   return ierr;
757 }
758 
759 PETSC_EXTERN PetscMPIInt PetscDataRep_read_conv_fn(void *userbuf, MPI_Datatype datatype,PetscMPIInt count,void *filebuf, MPI_Offset position,void *extra_state)
760 {
761   PetscDataType pdtype;
762   PetscMPIInt   ierr;
763   size_t        dsize;
764 
765   ierr = PetscMPIDataTypeToPetscDataType(datatype,&pdtype);CHKERRQ(ierr);
766   ierr = PetscDataTypeGetSize(pdtype,&dsize);CHKERRQ(ierr);
767 
768   /* offset is given in units of MPI_Datatype */
769   userbuf = ((char*)userbuf) + dsize*position;
770 
771   ierr = PetscMemcpy(userbuf,filebuf,count*dsize);CHKERRQ(ierr);
772   if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(userbuf,pdtype,count);CHKERRQ(ierr);}
773   return ierr;
774 }
775 
776 PetscMPIInt PetscDataRep_write_conv_fn(void *userbuf, MPI_Datatype datatype,PetscMPIInt count,void *filebuf, MPI_Offset position,void *extra_state)
777 {
778   PetscDataType pdtype;
779   PetscMPIInt   ierr;
780   size_t        dsize;
781 
782   ierr = PetscMPIDataTypeToPetscDataType(datatype,&pdtype);CHKERRQ(ierr);
783   ierr = PetscDataTypeGetSize(pdtype,&dsize);CHKERRQ(ierr);
784 
785   /* offset is given in units of MPI_Datatype */
786   userbuf = ((char*)userbuf) + dsize*position;
787 
788   ierr = PetscMemcpy(filebuf,userbuf,count*dsize);CHKERRQ(ierr);
789   if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(filebuf,pdtype,count);CHKERRQ(ierr);}
790   return ierr;
791 }
792 #endif
793 
794 PetscErrorCode MPIU_File_write_all(MPI_File fd,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
795 {
796   PetscDataType  pdtype;
797   PetscErrorCode ierr;
798 
799 
800   PetscFunctionBegin;
801   ierr = PetscMPIDataTypeToPetscDataType(dtype,&pdtype);CHKERRQ(ierr);
802   if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);}
803   ierr = MPI_File_write_all(fd,data,cnt,dtype,status);CHKERRQ(ierr);
804   if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);}
805   PetscFunctionReturn(0);
806 }
807 
808 PetscErrorCode MPIU_File_read_all(MPI_File fd,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
809 {
810   PetscDataType  pdtype;
811   PetscErrorCode ierr;
812 
813   PetscFunctionBegin;
814   ierr = PetscMPIDataTypeToPetscDataType(dtype,&pdtype);CHKERRQ(ierr);
815   ierr = MPI_File_read_all(fd,data,cnt,dtype,status);CHKERRQ(ierr);
816   if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);}
817   PetscFunctionReturn(0);
818 }
819 
820 PetscErrorCode MPIU_File_write_at(MPI_File fd,MPI_Offset off,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
821 {
822   PetscDataType  pdtype;
823   PetscErrorCode ierr;
824 
825 
826   PetscFunctionBegin;
827   ierr = PetscMPIDataTypeToPetscDataType(dtype,&pdtype);CHKERRQ(ierr);
828   if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);}
829   ierr = MPI_File_write_at(fd,off,data,cnt,dtype,status);CHKERRQ(ierr);
830   if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);}
831   PetscFunctionReturn(0);
832 }
833 
834 PetscErrorCode MPIU_File_read_at(MPI_File fd,MPI_Offset off,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
835 {
836   PetscDataType  pdtype;
837   PetscErrorCode ierr;
838 
839   PetscFunctionBegin;
840   ierr = PetscMPIDataTypeToPetscDataType(dtype,&pdtype);CHKERRQ(ierr);
841   ierr = MPI_File_read_at(fd,off,data,cnt,dtype,status);CHKERRQ(ierr);
842   if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);}
843   PetscFunctionReturn(0);
844 }
845 
846 PetscErrorCode MPIU_File_write_at_all(MPI_File fd,MPI_Offset off,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
847 {
848   PetscDataType  pdtype;
849   PetscErrorCode ierr;
850 
851 
852   PetscFunctionBegin;
853   ierr = PetscMPIDataTypeToPetscDataType(dtype,&pdtype);CHKERRQ(ierr);
854   if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);}
855   ierr = MPI_File_write_at_all(fd,off,data,cnt,dtype,status);CHKERRQ(ierr);
856   if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);}
857   PetscFunctionReturn(0);
858 }
859 
860 PetscErrorCode MPIU_File_read_at_all(MPI_File fd,MPI_Offset off,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
861 {
862   PetscDataType  pdtype;
863   PetscErrorCode ierr;
864 
865   PetscFunctionBegin;
866   ierr = PetscMPIDataTypeToPetscDataType(dtype,&pdtype);CHKERRQ(ierr);
867   ierr = MPI_File_read_at_all(fd,off,data,cnt,dtype,status);CHKERRQ(ierr);
868   if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);}
869   PetscFunctionReturn(0);
870 }
871 
872 #endif
873