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