xref: /petsc/src/sys/fileio/sysio.c (revision b72fa766f129fc2bd79867a41d61fdbe3fc875c4)
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_",0};
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 
241 
242    Level: developer
243 
244    Notes:
245    If count is not provided and the number of items read is less than
246    the maximum number of items to read, then this routine errors.
247 
248    PetscBinaryRead() uses byte swapping to work on all machines; the files
249    are written to file ALWAYS using big-endian ordering. On small-endian machines the numbers
250    are converted to the small-endian format when they are read in from the file.
251    When PETSc is ./configure with --with-64bit-indices the integers are written to the
252    file as 64 bit integers, this means they can only be read back in when the option --with-64bit-indices
253    is used.
254 
255    Concepts: files^reading binary
256    Concepts: binary files^reading
257 
258 .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscViewerBinaryGetDescriptor(), PetscBinarySynchronizedWrite(),
259           PetscBinarySynchronizedRead(), PetscBinarySynchronizedSeek()
260 @*/
261 PetscErrorCode  PetscBinaryRead(int fd,void *data,PetscInt num,PetscInt *count,PetscDataType type)
262 {
263   size_t            typesize, m = (size_t) num, n = 0, maxblock = 65536;
264   char              *p = (char*)data;
265 #if defined(PETSC_USE_REAL___FLOAT128)
266   PetscBool         readdouble = PETSC_FALSE;
267   double            *pdouble;
268 #endif
269 #if !defined(PETSC_WORDS_BIGENDIAN)
270   void              *ptmp = data;
271 #endif
272   char              *fname = NULL;
273   PetscErrorCode    ierr;
274 
275   PetscFunctionBegin;
276   if (count) *count = 0;
277   if (num < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Trying to read a negative amount of data %D",num);
278   if (!num) PetscFunctionReturn(0);
279 
280   if (type == PETSC_FUNCTION) {
281     m     = 64;
282     type  = PETSC_CHAR;
283     fname = (char*)malloc(m*sizeof(char));
284     p     = (char*)fname;
285 #if !defined(PETSC_WORDS_BIGENDIAN)
286     ptmp  = (void*)fname;
287 #endif
288     if (!fname) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Cannot allocate space for function name");
289   }
290   if (type == PETSC_BIT_LOGICAL) m = PetscBTLength(m);
291 
292   ierr = PetscDataTypeGetSize(type,&typesize);CHKERRQ(ierr);
293 
294 #if defined(PETSC_USE_REAL___FLOAT128)
295   ierr = PetscOptionsGetBool(NULL,NULL,"-binary_read_double",&readdouble,NULL);CHKERRQ(ierr);
296   /* If using __float128 precision we still read in doubles from file */
297   if ((type == PETSC_REAL || type == PETSC_COMPLEX) && readdouble) {
298     PetscInt cnt = num * ((type == PETSC_REAL) ? 1 : 2);
299     ierr = PetscMalloc1(cnt,&pdouble);CHKERRQ(ierr);
300     p = (char*)pdouble;
301     typesize /= 2;
302   }
303 #endif
304 
305   m *= typesize;
306 
307   while (m) {
308     size_t len = (m < maxblock) ? m : maxblock;
309     int    ret = (int)read(fd,p,len);
310     if (ret < 0 && errno == EINTR) continue;
311     if (!ret && len > 0) break; /* Proxy for EOF */
312     if (ret < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_READ,"Error reading from file, errno %d",errno);
313     m -= ret;
314     p += ret;
315     n += ret;
316   }
317   if (m && !count) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_READ,"Read past end of file");
318 
319   num = (PetscInt)(n/typesize); /* Should we require `n % typesize == 0` ? */
320   if (count) *count = num;      /* TODO: This is most likely wrong for PETSC_BIT_LOGICAL */
321 
322 #if defined(PETSC_USE_REAL___FLOAT128)
323   if ((type == PETSC_REAL || type == PETSC_COMPLEX) && readdouble) {
324     PetscInt  i, cnt = num * ((type == PETSC_REAL) ? 1 : 2);
325     PetscReal *preal = (PetscReal*)data;
326 #if !defined(PETSC_WORDS_BIGENDIAN)
327     ierr = PetscByteSwapDouble(pdouble,cnt);CHKERRQ(ierr);
328 #endif
329     for (i=0; i<cnt; i++) preal[i] = pdouble[i];
330     ierr = PetscFree(pdouble);CHKERRQ(ierr);
331     PetscFunctionReturn(0);
332   }
333 #endif
334 
335 #if !defined(PETSC_WORDS_BIGENDIAN)
336   ierr = PetscByteSwap(ptmp,type,num);CHKERRQ(ierr);
337 #endif
338 
339   if (type == PETSC_FUNCTION) {
340 #if defined(PETSC_SERIALIZE_FUNCTIONS)
341     ierr = PetscDLSym(NULL,fname,(void**)data);CHKERRQ(ierr);
342 #else
343     *(void**)data = NULL;
344 #endif
345     free(fname);
346   }
347   PetscFunctionReturn(0);
348 }
349 
350 /*@
351    PetscBinaryWrite - Writes to a binary file.
352 
353    Not Collective
354 
355    Input Parameters:
356 +  fd     - the file
357 .  p      - the buffer
358 .  n      - the number of items to write
359 .  type   - the type of items to read (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)
360 -  istemp - PETSC_FALSE if buffer data should be preserved, PETSC_TRUE otherwise.
361 
362    Level: advanced
363 
364    Notes:
365    PetscBinaryWrite() uses byte swapping to work on all machines; the files
366    are written using big-endian ordering to the file. On small-endian machines the numbers
367    are converted to the big-endian format when they are written to disk.
368    When PETSc is ./configure with --with-64bit-indices the integers are written to the
369    file as 64 bit integers, this means they can only be read back in when the option --with-64bit-indices
370    is used.
371 
372    If running with __float128 precision the output is in __float128 unless one uses the -binary_write_double option
373 
374    The Buffer p should be read-write buffer, and not static data.
375    This way, byte-swapping is done in-place, and then the buffer is
376    written to the file.
377 
378    This routine restores the original contents of the buffer, after
379    it is written to the file. This is done by byte-swapping in-place
380    the second time. If the flag istemp is set to PETSC_TRUE, the second
381    byte-swapping operation is not done, thus saving some computation,
382    but the buffer is left corrupted.
383 
384    Because byte-swapping may be done on the values in data it cannot be declared const
385 
386    Concepts: files^writing binary
387    Concepts: binary files^writing
388 
389 .seealso: PetscBinaryRead(), PetscBinaryOpen(), PetscBinaryClose(), PetscViewerBinaryGetDescriptor(), PetscBinarySynchronizedWrite(),
390           PetscBinarySynchronizedRead(), PetscBinarySynchronizedSeek()
391 @*/
392 PetscErrorCode  PetscBinaryWrite(int fd,void *p,PetscInt n,PetscDataType type,PetscBool  istemp)
393 {
394   char           *pp = (char*)p;
395   int            err,wsize;
396   size_t         m = (size_t)n,maxblock=65536;
397   PetscErrorCode ierr;
398 #if !defined(PETSC_WORDS_BIGENDIAN)
399   void           *ptmp = p;
400 #endif
401   char           *fname = NULL;
402 #if defined(PETSC_USE_REAL___FLOAT128)
403   PetscBool      writedouble = PETSC_FALSE;
404   double         *ppp;
405   PetscReal      *pv;
406   PetscInt       i;
407 #endif
408   PetscDataType  wtype = type;
409 
410   PetscFunctionBegin;
411   if (n < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Trying to write a negative amount of data %D",n);
412   if (!n) PetscFunctionReturn(0);
413 
414   if (type == PETSC_FUNCTION) {
415 #if defined(PETSC_SERIALIZE_FUNCTIONS)
416     const char *fnametmp;
417 #endif
418     m     = 64;
419     fname = (char*)malloc(m*sizeof(char));
420     if (!fname) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Cannot allocate space for function name");
421 #if defined(PETSC_SERIALIZE_FUNCTIONS)
422     if (n > 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Can only binary view a single function at a time");
423     ierr = PetscFPTFind(*(void**)p,&fnametmp);CHKERRQ(ierr);
424     ierr = PetscStrncpy(fname,fnametmp,m);CHKERRQ(ierr);
425 #else
426     ierr = PetscStrncpy(fname,"",m);CHKERRQ(ierr);
427 #endif
428     wtype = PETSC_CHAR;
429     pp    = (char*)fname;
430 #if !defined(PETSC_WORDS_BIGENDIAN)
431     ptmp  = (void*)fname;
432 #endif
433   }
434 
435 #if defined(PETSC_USE_REAL___FLOAT128)
436   ierr = PetscOptionsGetBool(NULL,NULL,"-binary_write_double",&writedouble,NULL);CHKERRQ(ierr);
437   /* If using __float128 precision we still write in doubles to file */
438   if ((type == PETSC_SCALAR || type == PETSC_REAL) && writedouble) {
439     wtype = PETSC_DOUBLE;
440     ierr = PetscMalloc1(n,&ppp);CHKERRQ(ierr);
441     pv = (PetscReal*)pp;
442     for (i=0; i<n; i++) {
443       ppp[i] = (double) pv[i];
444     }
445     pp   = (char*)ppp;
446     ptmp = (char*)ppp;
447   }
448 #endif
449 
450   if (wtype == PETSC_INT)          m *= sizeof(PetscInt);
451   else if (wtype == PETSC_SCALAR)  m *= sizeof(PetscScalar);
452   else if (wtype == PETSC_REAL)    m *= sizeof(PetscReal);
453   else if (wtype == PETSC_DOUBLE)  m *= sizeof(double);
454   else if (wtype == PETSC_FLOAT)   m *= sizeof(float);
455   else if (wtype == PETSC_SHORT)   m *= sizeof(short);
456   else if (wtype == PETSC_LONG)    m *= sizeof(long);
457   else if (wtype == PETSC_CHAR)    m *= sizeof(char);
458   else if (wtype == PETSC_ENUM)    m *= sizeof(PetscEnum);
459   else if (wtype == PETSC_BOOL)    m *= sizeof(PetscBool);
460   else if (wtype == PETSC_INT64)   m *= sizeof(PetscInt64);
461   else if (wtype == PETSC_BIT_LOGICAL) m = PetscBTLength(m)*sizeof(char);
462   else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Unknown type");
463 
464 #if !defined(PETSC_WORDS_BIGENDIAN)
465   ierr = PetscByteSwap(ptmp,wtype,n);CHKERRQ(ierr);
466 #endif
467 
468   while (m) {
469     wsize = (m < maxblock) ? m : maxblock;
470     err   = write(fd,pp,wsize);
471     if (err < 0 && errno == EINTR) continue;
472     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);
473     m  -= wsize;
474     pp += wsize;
475   }
476 
477 #if !defined(PETSC_WORDS_BIGENDIAN)
478   if (!istemp) {
479     ierr = PetscByteSwap(ptmp,wtype,n);CHKERRQ(ierr);
480   }
481 #endif
482   if (type == PETSC_FUNCTION) {
483     free(fname);
484   }
485 #if defined(PETSC_USE_REAL___FLOAT128)
486   if ((type == PETSC_SCALAR || type == PETSC_REAL) && writedouble) {
487     ierr = PetscFree(ppp);CHKERRQ(ierr);
488   }
489 #endif
490   PetscFunctionReturn(0);
491 }
492 
493 /*@C
494    PetscBinaryOpen - Opens a PETSc binary file.
495 
496    Not Collective
497 
498    Input Parameters:
499 +  name - filename
500 -  type - type of binary file, one of FILE_MODE_READ, FILE_MODE_APPEND, FILE_MODE_WRITE
501 
502    Output Parameter:
503 .  fd - the file
504 
505    Level: advanced
506 
507   Concepts: files^opening binary
508   Concepts: binary files^opening
509 
510    Notes:
511     Files access with PetscBinaryRead() and PetscBinaryWrite() are ALWAYS written in
512    big-endian format. This means the file can be accessed using PetscBinaryOpen() and
513    PetscBinaryRead() and PetscBinaryWrite() on any machine.
514 
515 .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscFileMode, PetscViewerFileSetMode(), PetscViewerBinaryGetDescriptor(),
516           PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(), PetscBinarySynchronizedSeek()
517 
518 @*/
519 PetscErrorCode  PetscBinaryOpen(const char name[],PetscFileMode mode,int *fd)
520 {
521   PetscFunctionBegin;
522 #if defined(PETSC_HAVE_O_BINARY)
523   if (mode == FILE_MODE_WRITE) {
524     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);
525   } else if (mode == FILE_MODE_READ) {
526     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);
527   } else if (mode == FILE_MODE_APPEND) {
528     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);
529 #else
530   if (mode == FILE_MODE_WRITE) {
531     if ((*fd = creat(name,0666)) == -1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot create file for writing: %s",name);
532   } else if (mode == FILE_MODE_READ) {
533     if ((*fd = open(name,O_RDONLY,0)) == -1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot open file for reading: %s",name);
534   }
535   else if (mode == FILE_MODE_APPEND) {
536     if ((*fd = open(name,O_WRONLY,0)) == -1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot open file for writing: %s",name);
537 #endif
538   } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Unknown file mode");
539   PetscFunctionReturn(0);
540 }
541 
542 /*@
543    PetscBinaryClose - Closes a PETSc binary file.
544 
545    Not Collective
546 
547    Output Parameter:
548 .  fd - the file
549 
550    Level: advanced
551 
552 .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(),
553           PetscBinarySynchronizedSeek()
554 @*/
555 PetscErrorCode  PetscBinaryClose(int fd)
556 {
557   PetscFunctionBegin;
558   close(fd);
559   PetscFunctionReturn(0);
560 }
561 
562 
563 /*@C
564    PetscBinarySeek - Moves the file pointer on a PETSc binary file.
565 
566    Not Collective
567 
568    Input Parameters:
569 +  fd - the file
570 .  off - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE,
571             etc. in your calculation rather than sizeof() to compute byte lengths.
572 -  whence - if PETSC_BINARY_SEEK_SET then off is an absolute location in the file
573             if PETSC_BINARY_SEEK_CUR then off is an offset from the current location
574             if PETSC_BINARY_SEEK_END then off is an offset from the end of file
575 
576    Output Parameter:
577 .   offset - new offset in file
578 
579    Level: developer
580 
581    Notes:
582    Integers are stored on the file as 32 long, regardless of whether
583    they are stored in the machine as 32 or 64, this means the same
584    binary file may be read on any machine. Hence you CANNOT use sizeof()
585    to determine the offset or location.
586 
587    Concepts: files^binary seeking
588    Concepts: binary files^seeking
589 
590 .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(),
591           PetscBinarySynchronizedSeek()
592 @*/
593 PetscErrorCode  PetscBinarySeek(int fd,off_t off,PetscBinarySeekType whence,off_t *offset)
594 {
595   int iwhence = 0;
596 
597   PetscFunctionBegin;
598   if (whence == PETSC_BINARY_SEEK_SET) iwhence = SEEK_SET;
599   else if (whence == PETSC_BINARY_SEEK_CUR) iwhence = SEEK_CUR;
600   else if (whence == PETSC_BINARY_SEEK_END) iwhence = SEEK_END;
601   else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Unknown seek location");
602 #if defined(PETSC_HAVE_LSEEK)
603   *offset = lseek(fd,off,iwhence);
604 #elif defined(PETSC_HAVE__LSEEK)
605   *offset = _lseek(fd,(long)off,iwhence);
606 #else
607   SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP_SYS,"System does not have a way of seeking on a file");
608 #endif
609   PetscFunctionReturn(0);
610 }
611 
612 /*@C
613    PetscBinarySynchronizedRead - Reads from a binary file.
614 
615    Collective on MPI_Comm
616 
617    Input Parameters:
618 +  comm - the MPI communicator
619 .  fd - the file descriptor
620 .  num  - the maximum number of items to read
621 -  type - the type of items to read (PETSC_INT, PETSC_REAL, PETSC_SCALAR, etc.)
622 
623    Output Parameters:
624 +  data - the buffer
625 -  count - the number of items read, optional
626 
627    Level: developer
628 
629    Notes:
630    Does a PetscBinaryRead() followed by an MPI_Bcast()
631 
632    If count is not provided and the number of items read is less than
633    the maximum number of items to read, then this routine errors.
634 
635    PetscBinarySynchronizedRead() uses byte swapping to work on all machines.
636    Integers are stored on the file as 32 long, regardless of whether
637    they are stored in the machine as 32 or 64, this means the same
638    binary file may be read on any machine.
639 
640    Concepts: files^synchronized reading of binary files
641    Concepts: binary files^reading, synchronized
642 
643 .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead(), PetscBinarySynchronizedWrite(),
644           PetscBinarySynchronizedSeek()
645 @*/
646 PetscErrorCode  PetscBinarySynchronizedRead(MPI_Comm comm,int fd,void *data,PetscInt num,PetscInt *count,PetscDataType type)
647 {
648   PetscErrorCode ierr;
649   PetscMPIInt    rank;
650   MPI_Datatype   mtype;
651   PetscInt       ibuf[2] = {0, 0};
652   char           *fname = NULL;
653   void           *fptr = NULL;
654 
655   PetscFunctionBegin;
656   if (type == PETSC_FUNCTION) {
657     num   = 64;
658     type  = PETSC_CHAR;
659     fname = (char*)malloc(num*sizeof(char));
660     fptr  = data;
661     data  = (void*)fname;
662     if (!fname) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Cannot allocate space for function name");
663   }
664 
665   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
666   if (!rank) {
667     ibuf[0] = PetscBinaryRead(fd,data,num,count?&ibuf[1]:NULL,type);
668   }
669   ierr = MPI_Bcast(ibuf,2,MPIU_INT,0,comm);CHKERRQ(ierr);
670   ierr = (PetscErrorCode)ibuf[0];CHKERRQ(ierr);
671   ierr = PetscDataTypeToMPIDataType(type,&mtype);CHKERRQ(ierr);
672   ierr = MPI_Bcast(data,count?ibuf[1]:num,mtype,0,comm);CHKERRQ(ierr);
673   if (count) *count = ibuf[1];
674 
675   if (type == PETSC_FUNCTION) {
676 #if defined(PETSC_SERIALIZE_FUNCTIONS)
677     ierr = PetscDLLibrarySym(PETSC_COMM_SELF,&PetscDLLibrariesLoaded,NULL,fname,(void**)fptr);CHKERRQ(ierr);
678 #else
679     *(void**)fptr = NULL;
680 #endif
681     free(fname);
682   }
683   PetscFunctionReturn(0);
684 }
685 
686 /*@C
687    PetscBinarySynchronizedWrite - writes to a binary file.
688 
689    Collective on MPI_Comm
690 
691    Input Parameters:
692 +  comm - the MPI communicator
693 .  fd - the file
694 .  n  - the number of items to write
695 .  p - the buffer
696 .  istemp - the buffer may be changed
697 -  type - the type of items to write (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)
698 
699    Level: developer
700 
701    Notes:
702    Process 0 does a PetscBinaryWrite()
703 
704    PetscBinarySynchronizedWrite() uses byte swapping to work on all machines.
705    Integers are stored on the file as 32 long, regardless of whether
706    they are stored in the machine as 32 or 64, this means the same
707    binary file may be read on any machine.
708 
709    Notes:
710     because byte-swapping may be done on the values in data it cannot be declared const
711 
712    WARNING: This is NOT like PetscSynchronizedFPrintf()! This routine ignores calls on all but process 0,
713    while PetscSynchronizedFPrintf() has all processes print their strings in order.
714 
715    Concepts: files^synchronized writing of binary files
716    Concepts: binary files^reading, synchronized
717 
718 .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead(), PetscBinarySynchronizedRead(),
719           PetscBinarySynchronizedSeek()
720 @*/
721 PetscErrorCode  PetscBinarySynchronizedWrite(MPI_Comm comm,int fd,void *p,PetscInt n,PetscDataType type,PetscBool istemp)
722 {
723   PetscErrorCode ierr;
724   PetscMPIInt    rank;
725 
726   PetscFunctionBegin;
727   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
728   if (!rank) {
729     ierr = PetscBinaryWrite(fd,p,n,type,istemp);CHKERRQ(ierr);
730   }
731   PetscFunctionReturn(0);
732 }
733 
734 /*@C
735    PetscBinarySynchronizedSeek - Moves the file pointer on a PETSc binary file.
736 
737 
738    Input Parameters:
739 +  fd - the file
740 .  whence - if PETSC_BINARY_SEEK_SET then size is an absolute location in the file
741             if PETSC_BINARY_SEEK_CUR then size is offset from current location
742             if PETSC_BINARY_SEEK_END then size is offset from end of file
743 -  off    - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE,
744             etc. in your calculation rather than sizeof() to compute byte lengths.
745 
746    Output Parameter:
747 .   offset - new offset in file
748 
749    Level: developer
750 
751    Notes:
752    Integers are stored on the file as 32 long, regardless of whether
753    they are stored in the machine as 32 or 64, this means the same
754    binary file may be read on any machine. Hence you CANNOT use sizeof()
755    to determine the offset or location.
756 
757    Concepts: binary files^seeking
758    Concepts: files^seeking in binary
759 
760 .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(),
761           PetscBinarySynchronizedSeek()
762 @*/
763 PetscErrorCode  PetscBinarySynchronizedSeek(MPI_Comm comm,int fd,off_t off,PetscBinarySeekType whence,off_t *offset)
764 {
765   PetscErrorCode ierr;
766   PetscMPIInt    rank;
767 
768   PetscFunctionBegin;
769   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
770   if (!rank) {
771     ierr = PetscBinarySeek(fd,off,whence,offset);CHKERRQ(ierr);
772   }
773   PetscFunctionReturn(0);
774 }
775 
776 #if defined(PETSC_HAVE_MPIIO)
777 #if !defined(PETSC_WORDS_BIGENDIAN)
778 
779 #if defined(PETSC_USE_PETSC_MPI_EXTERNAL32)
780 /*
781       MPICH does not provide the external32 representation for MPI_File_set_view() so we need to provide the functions.
782     These are set into MPI in PetscInitialize() via MPI_Register_datarep()
783 
784     Note I use PetscMPIInt for the MPI error codes since that is what MPI uses (instead of the standard PetscErrorCode)
785 
786     The next three routines are not used because MPICH does not support their use
787 
788 */
789 PETSC_EXTERN PetscMPIInt PetscDataRep_extent_fn(MPI_Datatype datatype,MPI_Aint *file_extent,void *extra_state)
790 {
791   MPI_Aint    ub;
792   PetscMPIInt ierr;
793 
794   ierr = MPI_Type_get_extent(datatype,&ub,file_extent);
795   return ierr;
796 }
797 
798 PETSC_EXTERN PetscMPIInt PetscDataRep_read_conv_fn(void *userbuf, MPI_Datatype datatype,PetscMPIInt count,void *filebuf, MPI_Offset position,void *extra_state)
799 {
800   PetscDataType pdtype;
801   PetscMPIInt   ierr;
802   size_t        dsize;
803 
804   ierr = PetscMPIDataTypeToPetscDataType(datatype,&pdtype);CHKERRQ(ierr);
805   ierr = PetscDataTypeGetSize(pdtype,&dsize);CHKERRQ(ierr);
806 
807   /* offset is given in units of MPI_Datatype */
808   userbuf = ((char*)userbuf) + dsize*position;
809 
810   ierr = PetscMemcpy(userbuf,filebuf,count*dsize);CHKERRQ(ierr);
811   ierr = PetscByteSwap(userbuf,pdtype,count);CHKERRQ(ierr);
812   return ierr;
813 }
814 
815 PetscMPIInt PetscDataRep_write_conv_fn(void *userbuf, MPI_Datatype datatype,PetscMPIInt count,void *filebuf, MPI_Offset position,void *extra_state)
816 {
817   PetscDataType pdtype;
818   PetscMPIInt   ierr;
819   size_t        dsize;
820 
821   ierr = PetscMPIDataTypeToPetscDataType(datatype,&pdtype);CHKERRQ(ierr);
822   ierr = PetscDataTypeGetSize(pdtype,&dsize);CHKERRQ(ierr);
823 
824   /* offset is given in units of MPI_Datatype */
825   userbuf = ((char*)userbuf) + dsize*position;
826 
827   ierr = PetscMemcpy(filebuf,userbuf,count*dsize);CHKERRQ(ierr);
828   ierr = PetscByteSwap(filebuf,pdtype,count);CHKERRQ(ierr);
829   return ierr;
830 }
831 #endif
832 
833 PetscErrorCode MPIU_File_write_all(MPI_File fd,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
834 {
835   PetscErrorCode ierr;
836   PetscDataType  pdtype;
837 
838   PetscFunctionBegin;
839   ierr = PetscMPIDataTypeToPetscDataType(dtype,&pdtype);CHKERRQ(ierr);
840   ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);
841   ierr = MPI_File_write_all(fd,data,cnt,dtype,status);CHKERRQ(ierr);
842   ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);
843   PetscFunctionReturn(0);
844 }
845 
846 PetscErrorCode MPIU_File_read_all(MPI_File fd,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
847 {
848   PetscErrorCode ierr;
849   PetscDataType  pdtype;
850 
851   PetscFunctionBegin;
852   ierr = PetscMPIDataTypeToPetscDataType(dtype,&pdtype);CHKERRQ(ierr);
853   ierr = MPI_File_read_all(fd,data,cnt,dtype,status);CHKERRQ(ierr);
854   ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);
855   PetscFunctionReturn(0);
856 }
857 #endif
858 #endif
859