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