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