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