xref: /petsc/src/sys/fileio/sysio.c (revision b24fb147d2f783efb2f58813f80260c02fe8ea96) !
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 - see `PetscBinarySeekType` for possible values
533 
534    Output Parameter:
535 .   offset - new offset in file
536 
537    Level: developer
538 
539    Note:
540    Integers are stored on the file as 32 long, regardless of whether
541    they are stored in the machine as 32 or 64, this means the same
542    binary file may be read on any machine. Hence you CANNOT use `sizeof()`
543    to determine the offset or location.
544 
545 .seealso: `PetscBinaryRead()`, `PetscBinarySeekType`, `PetscBinaryWrite()`, `PetscBinaryOpen()`, `PetscBinarySynchronizedWrite()`, `PetscBinarySynchronizedRead()`,
546           `PetscBinarySynchronizedSeek()`
547 @*/
548 PetscErrorCode PetscBinarySeek(int fd, off_t off, PetscBinarySeekType whence, off_t *offset)
549 {
550   int iwhence = 0;
551 
552   PetscFunctionBegin;
553   if (whence == PETSC_BINARY_SEEK_SET) iwhence = SEEK_SET;
554   else if (whence == PETSC_BINARY_SEEK_CUR) iwhence = SEEK_CUR;
555   else if (whence == PETSC_BINARY_SEEK_END) iwhence = SEEK_END;
556   else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Unknown seek location");
557 #if defined(PETSC_HAVE_LSEEK)
558   *offset = lseek(fd, off, iwhence);
559 #elif defined(PETSC_HAVE__LSEEK)
560   *offset = _lseek(fd, (long)off, iwhence);
561 #else
562   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "System does not have a way of seeking on a file");
563 #endif
564   PetscFunctionReturn(PETSC_SUCCESS);
565 }
566 
567 /*@C
568    PetscBinarySynchronizedRead - Reads from a binary file.
569 
570    Collective
571 
572    Input Parameters:
573 +  comm - the MPI communicator
574 .  fd - the file descriptor
575 .  num  - the maximum number of items to read
576 -  type - the type of items to read (`PETSC_INT`, `PETSC_REAL`, `PETSC_SCALAR`, etc.)
577 
578    Output Parameters:
579 +  data - the buffer
580 -  count - the number of items read, optional
581 
582    Level: developer
583 
584    Notes:
585    Does a `PetscBinaryRead()` followed by an `MPI_Bcast()`
586 
587    If count is not provided and the number of items read is less than
588    the maximum number of items to read, then this routine errors.
589 
590    `PetscBinarySynchronizedRead()` uses byte swapping to work on all machines.
591    Integers are stored on the file as 32 long, regardless of whether
592    they are stored in the machine as 32 or 64, this means the same
593    binary file may be read on any machine.
594 
595 .seealso: `PetscBinaryWrite()`, `PetscBinaryOpen()`, `PetscBinaryClose()`, `PetscBinaryRead()`, `PetscBinarySynchronizedWrite()`,
596           `PetscBinarySynchronizedSeek()`
597 @*/
598 PetscErrorCode PetscBinarySynchronizedRead(MPI_Comm comm, int fd, void *data, PetscInt num, PetscInt *count, PetscDataType type)
599 {
600   PetscMPIInt  rank, size;
601   MPI_Datatype mtype;
602   PetscInt     ibuf[2] = {0, 0};
603   char        *fname   = NULL;
604   void        *fptr    = NULL;
605 
606   PetscFunctionBegin;
607   if (type == PETSC_FUNCTION) {
608     num   = 64;
609     type  = PETSC_CHAR;
610     fname = (char *)malloc(num * sizeof(char));
611     fptr  = data;
612     data  = (void *)fname;
613     PetscCheck(fname, PETSC_COMM_SELF, PETSC_ERR_MEM, "Cannot allocate space for function name");
614   }
615 
616   PetscCallMPI(MPI_Comm_rank(comm, &rank));
617   PetscCallMPI(MPI_Comm_size(comm, &size));
618   if (rank == 0) ibuf[0] = PetscBinaryRead(fd, data, num, count ? &ibuf[1] : NULL, type);
619   PetscCallMPI(MPI_Bcast(ibuf, 2, MPIU_INT, 0, comm));
620   PetscCall((PetscErrorCode)ibuf[0]);
621 
622   /* 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 */
623   if (size > 1) {
624     PetscCall(PetscDataTypeToMPIDataType(type, &mtype));
625     PetscCallMPI(MPI_Bcast(data, count ? ibuf[1] : num, mtype, 0, comm));
626   }
627   if (count) *count = ibuf[1];
628 
629   if (type == PETSC_FUNCTION) {
630 #if defined(PETSC_SERIALIZE_FUNCTIONS)
631     PetscCall(PetscDLLibrarySym(PETSC_COMM_SELF, &PetscDLLibrariesLoaded, NULL, fname, (void **)fptr));
632 #else
633     *(void **)fptr = NULL;
634 #endif
635     free(fname);
636   }
637   PetscFunctionReturn(PETSC_SUCCESS);
638 }
639 
640 /*@C
641    PetscBinarySynchronizedWrite - writes to a binary file.
642 
643    Collective
644 
645    Input Parameters:
646 +  comm - the MPI communicator
647 .  fd - the file
648 .  n  - the number of items to write
649 .  p - the buffer
650 -  type - the type of items to write (`PETSC_INT`, `PETSC_REAL` or `PETSC_SCALAR`)
651 
652    Level: developer
653 
654    Notes:
655    MPI rank 0 does a `PetscBinaryWrite()`
656 
657    `PetscBinarySynchronizedWrite()` uses byte swapping to work on all machines.
658    Integers are stored on the file as 32 long, regardless of whether
659    they are stored in the machine as 32 or 64, this means the same
660    binary file may be read on any machine.
661 
662    Because byte-swapping may be done on the values in data it cannot be declared const
663 
664    WARNING:
665    This is NOT like `PetscSynchronizedFPrintf()`! This routine ignores calls on all but MPI rank 0,
666    while `PetscSynchronizedFPrintf()` has all processes print their strings in order.
667 
668 .seealso: `PetscBinaryWrite()`, `PetscBinaryOpen()`, `PetscBinaryClose()`, `PetscBinaryRead()`, `PetscBinarySynchronizedRead()`,
669           `PetscBinarySynchronizedSeek()`
670 @*/
671 PetscErrorCode PetscBinarySynchronizedWrite(MPI_Comm comm, int fd, const void *p, PetscInt n, PetscDataType type)
672 {
673   PetscMPIInt rank;
674 
675   PetscFunctionBegin;
676   PetscCallMPI(MPI_Comm_rank(comm, &rank));
677   if (rank == 0) PetscCall(PetscBinaryWrite(fd, p, n, type));
678   PetscFunctionReturn(PETSC_SUCCESS);
679 }
680 
681 /*@C
682    PetscBinarySynchronizedSeek - Moves the file pointer on a PETSc binary file.
683 
684    Input Parameters:
685 +  fd - the file
686 .  whence -  see `PetscBinarySeekType` for possible values
687 -  off    - number of bytes to move. Use `PETSC_BINARY_INT_SIZE`, `PETSC_BINARY_SCALAR_SIZE`,
688             etc. in your calculation rather than `sizeof()` to compute byte lengths.
689 
690    Output Parameter:
691 .   offset - new offset in file
692 
693    Level: developer
694 
695    Note:
696    Integers are stored on the file as 32 long, regardless of whether
697    they are stored in the machine as 32 or 64, this means the same
698    binary file may be read on any machine. Hence you CANNOT use `sizeof()`
699    to determine the offset or location.
700 
701 .seealso: `PetscBinaryRead()`, `PetscBinarySeekType`, `PetscBinaryWrite()`, `PetscBinaryOpen()`, `PetscBinarySynchronizedWrite()`, `PetscBinarySynchronizedRead()`,
702           `PetscBinarySynchronizedSeek()`
703 @*/
704 PetscErrorCode PetscBinarySynchronizedSeek(MPI_Comm comm, int fd, off_t off, PetscBinarySeekType whence, off_t *offset)
705 {
706   PetscMPIInt rank;
707 
708   PetscFunctionBegin;
709   PetscCallMPI(MPI_Comm_rank(comm, &rank));
710   if (rank == 0) PetscCall(PetscBinarySeek(fd, off, whence, offset));
711   PetscFunctionReturn(PETSC_SUCCESS);
712 }
713 
714 #if defined(PETSC_HAVE_MPIIO)
715 
716   #if defined(PETSC_USE_PETSC_MPI_EXTERNAL32)
717 /*
718       MPICH does not provide the external32 representation for MPI_File_set_view() so we need to provide the functions.
719     These are set into MPI in PetscInitialize() via MPI_Register_datarep()
720 
721     Note I use PetscMPIInt for the MPI error codes since that is what MPI uses (instead of the standard PetscErrorCode)
722 
723     The next three routines are not used because MPICH does not support their use
724 
725 */
726 PETSC_EXTERN PetscMPIInt PetscDataRep_extent_fn(MPI_Datatype datatype, MPI_Aint *file_extent, void *extra_state)
727 {
728   MPI_Aint    ub;
729   PetscMPIInt ierr;
730 
731   ierr = MPI_Type_get_extent(datatype, &ub, file_extent);
732   return ierr;
733 }
734 
735 PETSC_EXTERN PetscMPIInt PetscDataRep_read_conv_fn(void *userbuf, MPI_Datatype datatype, PetscMPIInt count, void *filebuf, MPI_Offset position, void *extra_state)
736 {
737   PetscDataType pdtype;
738   PetscMPIInt   ierr;
739   size_t        dsize;
740 
741   PetscCall(PetscMPIDataTypeToPetscDataType(datatype, &pdtype));
742   PetscCall(PetscDataTypeGetSize(pdtype, &dsize));
743 
744   /* offset is given in units of MPI_Datatype */
745   userbuf = ((char *)userbuf) + dsize * position;
746 
747   PetscCall(PetscMemcpy(userbuf, filebuf, count * dsize));
748   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(userbuf, pdtype, count));
749   return ierr;
750 }
751 
752 PetscMPIInt PetscDataRep_write_conv_fn(void *userbuf, MPI_Datatype datatype, PetscMPIInt count, void *filebuf, MPI_Offset position, void *extra_state)
753 {
754   PetscDataType pdtype;
755   PetscMPIInt   ierr;
756   size_t        dsize;
757 
758   PetscCall(PetscMPIDataTypeToPetscDataType(datatype, &pdtype));
759   PetscCall(PetscDataTypeGetSize(pdtype, &dsize));
760 
761   /* offset is given in units of MPI_Datatype */
762   userbuf = ((char *)userbuf) + dsize * position;
763 
764   PetscCall(PetscMemcpy(filebuf, userbuf, count * dsize));
765   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(filebuf, pdtype, count));
766   return ierr;
767 }
768   #endif
769 
770 PetscErrorCode MPIU_File_write_all(MPI_File fd, void *data, PetscMPIInt cnt, MPI_Datatype dtype, MPI_Status *status)
771 {
772   PetscDataType pdtype;
773 
774   PetscFunctionBegin;
775   PetscCall(PetscMPIDataTypeToPetscDataType(dtype, &pdtype));
776   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
777   PetscCallMPI(MPI_File_write_all(fd, data, cnt, dtype, status));
778   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
779   PetscFunctionReturn(PETSC_SUCCESS);
780 }
781 
782 PetscErrorCode MPIU_File_read_all(MPI_File fd, void *data, PetscMPIInt cnt, MPI_Datatype dtype, MPI_Status *status)
783 {
784   PetscDataType pdtype;
785 
786   PetscFunctionBegin;
787   PetscCall(PetscMPIDataTypeToPetscDataType(dtype, &pdtype));
788   PetscCallMPI(MPI_File_read_all(fd, data, cnt, dtype, status));
789   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
790   PetscFunctionReturn(PETSC_SUCCESS);
791 }
792 
793 PetscErrorCode MPIU_File_write_at(MPI_File fd, MPI_Offset off, void *data, PetscMPIInt cnt, MPI_Datatype dtype, MPI_Status *status)
794 {
795   PetscDataType pdtype;
796 
797   PetscFunctionBegin;
798   PetscCall(PetscMPIDataTypeToPetscDataType(dtype, &pdtype));
799   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
800   PetscCallMPI(MPI_File_write_at(fd, off, data, cnt, dtype, status));
801   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
802   PetscFunctionReturn(PETSC_SUCCESS);
803 }
804 
805 PetscErrorCode MPIU_File_read_at(MPI_File fd, MPI_Offset off, void *data, PetscMPIInt cnt, MPI_Datatype dtype, MPI_Status *status)
806 {
807   PetscDataType pdtype;
808 
809   PetscFunctionBegin;
810   PetscCall(PetscMPIDataTypeToPetscDataType(dtype, &pdtype));
811   PetscCallMPI(MPI_File_read_at(fd, off, data, cnt, dtype, status));
812   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
813   PetscFunctionReturn(PETSC_SUCCESS);
814 }
815 
816 PetscErrorCode MPIU_File_write_at_all(MPI_File fd, MPI_Offset off, void *data, PetscMPIInt cnt, MPI_Datatype dtype, MPI_Status *status)
817 {
818   PetscDataType pdtype;
819 
820   PetscFunctionBegin;
821   PetscCall(PetscMPIDataTypeToPetscDataType(dtype, &pdtype));
822   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
823   PetscCallMPI(MPI_File_write_at_all(fd, off, data, cnt, dtype, status));
824   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
825   PetscFunctionReturn(PETSC_SUCCESS);
826 }
827 
828 PetscErrorCode MPIU_File_read_at_all(MPI_File fd, MPI_Offset off, void *data, PetscMPIInt cnt, MPI_Datatype dtype, MPI_Status *status)
829 {
830   PetscDataType pdtype;
831 
832   PetscFunctionBegin;
833   PetscCall(PetscMPIDataTypeToPetscDataType(dtype, &pdtype));
834   PetscCallMPI(MPI_File_read_at_all(fd, off, data, cnt, dtype, status));
835   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
836   PetscFunctionReturn(PETSC_SUCCESS);
837 }
838 
839 #endif
840