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