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