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