xref: /petsc/src/sys/fileio/sysio.c (revision 5c8f6a953e7ed1c81f507d64aebddb11080b60e9)
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 
331   PetscFunctionReturn(0);
332 }
333 /* --------------------------------------------------------- */
334 #undef __FUNCT__
335 #define __FUNCT__ "PetscBinaryWrite"
336 /*@
337    PetscBinaryWrite - Writes to a binary file.
338 
339    Not Collective
340 
341    Input Parameters:
342 +  fd     - the file
343 .  p      - the buffer
344 .  n      - the number of items to write
345 .  type   - the type of items to read (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)
346 -  istemp - PETSC_FALSE if buffer data should be preserved, PETSC_TRUE otherwise.
347 
348    Level: advanced
349 
350    Notes:
351    PetscBinaryWrite() uses byte swapping to work on all machines; the files
352    are written using big-endian ordering to the file. On small-endian machines the numbers
353    are converted to the big-endian format when they are written to disk.
354    When PETSc is ./configure with --with-64bit-indices the integers are written to the
355    file as 64 bit integers, this means they can only be read back in when the option --with-64bit-indices
356    is used.
357 
358    The Buffer p should be read-write buffer, and not static data.
359    This way, byte-swapping is done in-place, and then the buffer is
360    written to the file.
361 
362    This routine restores the original contents of the buffer, after
363    it is written to the file. This is done by byte-swapping in-place
364    the second time. If the flag istemp is set to PETSC_TRUE, the second
365    byte-swapping operation is not done, thus saving some computation,
366    but the buffer is left corrupted.
367 
368    Because byte-swapping may be done on the values in data it cannot be declared const
369 
370    Concepts: files^writing binary
371    Concepts: binary files^writing
372 
373 .seealso: PetscBinaryRead(), PetscBinaryOpen(), PetscBinaryClose(), PetscViewerBinaryGetDescriptor(), PetscBinarySynchronizedWrite(),
374           PetscBinarySynchronizedRead(), PetscBinarySynchronizedSeek()
375 @*/
376 PetscErrorCode  PetscBinaryWrite(int fd,void *p,PetscInt n,PetscDataType type,PetscBool  istemp)
377 {
378   char           *pp = (char*)p;
379   int            err,wsize;
380   size_t         m = (size_t)n,maxblock=65536;
381   PetscErrorCode ierr;
382 #if !defined(PETSC_WORDS_BIGENDIAN)
383   void           *ptmp = p;
384 #endif
385   char           fname[64];
386 
387   PetscFunctionBegin;
388   if (n < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Trying to write a negative amount of data %D",n);
389   if (!n) PetscFunctionReturn(0);
390 
391   if (type == PETSC_FUNCTION) {
392 #if defined(PETSC_SERIALIZE_FUNCTIONS)
393     const char *fnametmp;
394 
395     if (n > 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Can only binary view a single function at a time");
396     ierr = PetscFPTFind(p,&fnametmp);CHKERRQ(ierr);
397     ierr = PetscStrncpy(fname,fnametmp,64);CHKERRQ(ierr);
398 #else
399     ierr = PetscStrncpy(fname,"",64);CHKERRQ(ierr);
400 #endif
401     m    = 64;
402     type = PETSC_CHAR;
403     pp   = (char*)fname;
404 #if !defined(PETSC_WORDS_BIGENDIAN)
405     ptmp = (void*)fname;
406 #endif
407   }
408 
409   if (type == PETSC_INT)          m *= sizeof(PetscInt);
410   else if (type == PETSC_SCALAR)  m *= sizeof(PetscScalar);
411   else if (type == PETSC_DOUBLE)  m *= sizeof(double);
412   else if (type == PETSC_FLOAT)   m *= sizeof(float);
413   else if (type == PETSC_SHORT)   m *= sizeof(short);
414   else if (type == PETSC_CHAR)    m *= sizeof(char);
415   else if (type == PETSC_ENUM)    m *= sizeof(PetscEnum);
416   else if (type == PETSC_BOOL)   m *= sizeof(PetscBool);
417   else if (type == PETSC_BIT_LOGICAL) m = PetscBTLength(m)*sizeof(char);
418   else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Unknown type");
419 
420 #if !defined(PETSC_WORDS_BIGENDIAN)
421   ierr = PetscByteSwap(ptmp,type,n);CHKERRQ(ierr);
422 #endif
423 
424   while (m) {
425     wsize = (m < maxblock) ? m : maxblock;
426     err = write(fd,pp,wsize);
427     if (err < 0 && errno == EINTR) continue;
428     if (err != wsize) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_WRITE,"Error writing to file.");
429     m -= wsize;
430     pp += wsize;
431   }
432 
433 #if !defined(PETSC_WORDS_BIGENDIAN)
434   if (!istemp) {
435     ierr = PetscByteSwap(ptmp,type,n);CHKERRQ(ierr);
436   }
437 #endif
438   PetscFunctionReturn(0);
439 }
440 
441 #undef __FUNCT__
442 #define __FUNCT__ "PetscBinaryOpen"
443 /*@C
444    PetscBinaryOpen - Opens a PETSc binary file.
445 
446    Not Collective
447 
448    Input Parameters:
449 +  name - filename
450 -  type - type of binary file, one of FILE_MODE_READ, FILE_MODE_APPEND, FILE_MODE_WRITE
451 
452    Output Parameter:
453 .  fd - the file
454 
455    Level: advanced
456 
457   Concepts: files^opening binary
458   Concepts: binary files^opening
459 
460    Notes: Files access with PetscBinaryRead() and PetscBinaryWrite() are ALWAYS written in
461    big-endian format. This means the file can be accessed using PetscBinaryOpen() and
462    PetscBinaryRead() and PetscBinaryWrite() on any machine.
463 
464 .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscFileMode, PetscViewerFileSetMode(), PetscViewerBinaryGetDescriptor(),
465           PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(), PetscBinarySynchronizedSeek()
466 
467 @*/
468 PetscErrorCode  PetscBinaryOpen(const char name[],PetscFileMode mode,int *fd)
469 {
470   PetscFunctionBegin;
471 #if defined(PETSC_HAVE_O_BINARY)
472   if (mode == FILE_MODE_WRITE) {
473     if ((*fd = open(name,O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,0666)) == -1) {
474       SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot create file for writing: %s",name);
475     }
476   } else if (mode == FILE_MODE_READ) {
477     if ((*fd = open(name,O_RDONLY|O_BINARY,0)) == -1) {
478       SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot open file for reading: %s",name);
479     }
480   } else if (mode == FILE_MODE_APPEND) {
481     if ((*fd = open(name,O_WRONLY|O_BINARY,0)) == -1) {
482       SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot open file for writing: %s",name);
483     }
484 #else
485   if (mode == FILE_MODE_WRITE) {
486     if ((*fd = creat(name,0666)) == -1) {
487       SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot create file for writing: %s",name);
488     }
489   } else if (mode == FILE_MODE_READ) {
490     if ((*fd = open(name,O_RDONLY,0)) == -1) {
491       SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot open file for reading: %s",name);
492     }
493   }
494   else if (mode == FILE_MODE_APPEND) {
495     if ((*fd = open(name,O_WRONLY,0)) == -1) {
496       SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot open file for writing: %s",name);
497     }
498 #endif
499   } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Unknown file mode");
500   PetscFunctionReturn(0);
501 }
502 
503 #undef __FUNCT__
504 #define __FUNCT__ "PetscBinaryClose"
505 /*@
506    PetscBinaryClose - Closes a PETSc binary file.
507 
508    Not Collective
509 
510    Output Parameter:
511 .  fd - the file
512 
513    Level: advanced
514 
515 .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(),
516           PetscBinarySynchronizedSeek()
517 @*/
518 PetscErrorCode  PetscBinaryClose(int fd)
519 {
520   PetscFunctionBegin;
521   close(fd);
522   PetscFunctionReturn(0);
523 }
524 
525 
526 #undef __FUNCT__
527 #define __FUNCT__ "PetscBinarySeek"
528 /*@
529    PetscBinarySeek - Moves the file pointer on a PETSc binary file.
530 
531    Not Collective
532 
533    Input Parameters:
534 +  fd - the file
535 .  off - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE,
536             etc. in your calculation rather than sizeof() to compute byte lengths.
537 -  whence - if PETSC_BINARY_SEEK_SET then off is an absolute location in the file
538             if PETSC_BINARY_SEEK_CUR then off is an offset from the current location
539             if PETSC_BINARY_SEEK_END then off is an offset from the end of file
540 
541    Output Parameter:
542 .   offset - new offset in file
543 
544    Level: developer
545 
546    Notes:
547    Integers are stored on the file as 32 long, regardless of whether
548    they are stored in the machine as 32 or 64, this means the same
549    binary file may be read on any machine. Hence you CANNOT use sizeof()
550    to determine the offset or location.
551 
552    Concepts: files^binary seeking
553    Concepts: binary files^seeking
554 
555 .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(),
556           PetscBinarySynchronizedSeek()
557 @*/
558 PetscErrorCode  PetscBinarySeek(int fd,off_t off,PetscBinarySeekType whence,off_t *offset)
559 {
560   int iwhence = 0;
561 
562   PetscFunctionBegin;
563   if (whence == PETSC_BINARY_SEEK_SET) {
564     iwhence = SEEK_SET;
565   } else if (whence == PETSC_BINARY_SEEK_CUR) {
566     iwhence = SEEK_CUR;
567   } else if (whence == PETSC_BINARY_SEEK_END) {
568     iwhence = SEEK_END;
569   } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Unknown seek location");
570 #if defined(PETSC_HAVE_LSEEK)
571   *offset = lseek(fd,off,iwhence);
572 #elif defined(PETSC_HAVE__LSEEK)
573   *offset = _lseek(fd,(long)off,iwhence);
574 #else
575   SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP_SYS,"System does not have a way of seeking on a file");
576 #endif
577   PetscFunctionReturn(0);
578 }
579 
580 #undef __FUNCT__
581 #define __FUNCT__ "PetscBinarySynchronizedRead"
582 /*@C
583    PetscBinarySynchronizedRead - Reads from a binary file.
584 
585    Collective on MPI_Comm
586 
587    Input Parameters:
588 +  comm - the MPI communicator
589 .  fd - the file
590 .  n  - the number of items to read
591 -  type - the type of items to read (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)
592 
593    Output Parameters:
594 .  p - the buffer
595 
596    Options Database Key:
597 .   -binary_longints - indicates the file was generated on a Cray vector
598          machine (not the T3E/D) and the ints are stored as 64 bit
599          quantities, otherwise they are stored as 32 bit
600 
601    Level: developer
602 
603    Notes:
604    Does a PetscBinaryRead() followed by an MPI_Bcast()
605 
606    PetscBinarySynchronizedRead() uses byte swapping to work on all machines.
607    Integers are stored on the file as 32 long, regardless of whether
608    they are stored in the machine as 32 or 64, this means the same
609    binary file may be read on any machine.
610 
611    Concepts: files^synchronized reading of binary files
612    Concepts: binary files^reading, synchronized
613 
614 .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead(), PetscBinarySynchronizedWrite(),
615           PetscBinarySynchronizedSeek()
616 @*/
617 PetscErrorCode  PetscBinarySynchronizedRead(MPI_Comm comm,int fd,void *p,PetscInt n,PetscDataType type)
618 {
619   PetscErrorCode ierr;
620   PetscMPIInt    rank;
621   MPI_Datatype   mtype;
622   char           *fname;
623   PetscBool      functionload = PETSC_FALSE;
624   void           *ptmp = PETSC_NULL;
625 
626   PetscFunctionBegin;
627   if (type == PETSC_FUNCTION) {
628     functionload = PETSC_TRUE;
629     n            = 64;
630     type         = PETSC_CHAR;
631     ptmp         = p;
632     /* warning memory leak */
633     fname        = (char*)malloc(64*sizeof(char));
634     p            = (void*)fname;
635   }
636 
637   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
638   if (!rank) {
639     ierr = PetscBinaryRead(fd,p,n,type);CHKERRQ(ierr);
640   }
641   ierr = PetscDataTypeToMPIDataType(type,&mtype);CHKERRQ(ierr);
642   ierr = MPI_Bcast(p,n,mtype,0,comm);CHKERRQ(ierr);
643 
644   if (functionload) {
645 #if defined(PETSC_SERIALIZE_FUNCTIONS)
646     ierr = PetscDLLibrarySym(PETSC_COMM_SELF,&PetscDLLibrariesLoaded,PETSC_NULL,fname,(void**)ptmp);CHKERRQ(ierr);
647 #else
648     *(void**)ptmp = PETSC_NULL;
649 #endif
650   }
651   PetscFunctionReturn(0);
652 }
653 
654 #undef __FUNCT__
655 #define __FUNCT__ "PetscBinarySynchronizedWrite"
656 /*@C
657    PetscBinarySynchronizedWrite - writes to a binary file.
658 
659    Collective on MPI_Comm
660 
661    Input Parameters:
662 +  comm - the MPI communicator
663 .  fd - the file
664 .  n  - the number of items to write
665 .  p - the buffer
666 .  istemp - the buffer may be changed
667 -  type - the type of items to write (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)
668 
669    Level: developer
670 
671    Notes:
672    Process 0 does a PetscBinaryWrite()
673 
674    PetscBinarySynchronizedWrite() uses byte swapping to work on all machines.
675    Integers are stored on the file as 32 long, regardless of whether
676    they are stored in the machine as 32 or 64, this means the same
677    binary file may be read on any machine.
678 
679    Notes: because byte-swapping may be done on the values in data it cannot be declared const
680 
681    WARNING: This is NOT like PetscSynchronizedFPrintf()! This routine ignores calls on all but process 0,
682    while PetscSynchronizedFPrintf() has all processes print their strings in order.
683 
684    Concepts: files^synchronized writing of binary files
685    Concepts: binary files^reading, synchronized
686 
687 .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead(), PetscBinarySynchronizedRead(),
688           PetscBinarySynchronizedSeek()
689 @*/
690 PetscErrorCode  PetscBinarySynchronizedWrite(MPI_Comm comm,int fd,void *p,PetscInt n,PetscDataType type,PetscBool  istemp)
691 {
692   PetscErrorCode ierr;
693   PetscMPIInt    rank;
694 
695   PetscFunctionBegin;
696   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
697   if (!rank) {
698     ierr = PetscBinaryWrite(fd,p,n,type,istemp);CHKERRQ(ierr);
699   }
700   PetscFunctionReturn(0);
701 }
702 
703 #undef __FUNCT__
704 #define __FUNCT__ "PetscBinarySynchronizedSeek"
705 /*@C
706    PetscBinarySynchronizedSeek - Moves the file pointer on a PETSc binary file.
707 
708 
709    Input Parameters:
710 +  fd - the file
711 .  whence - if PETSC_BINARY_SEEK_SET then size is an absolute location in the file
712             if PETSC_BINARY_SEEK_CUR then size is offset from current location
713             if PETSC_BINARY_SEEK_END then size is offset from end of file
714 -  off    - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE,
715             etc. in your calculation rather than sizeof() to compute byte lengths.
716 
717    Output Parameter:
718 .   offset - new offset in file
719 
720    Level: developer
721 
722    Notes:
723    Integers are stored on the file as 32 long, regardless of whether
724    they are stored in the machine as 32 or 64, this means the same
725    binary file may be read on any machine. Hence you CANNOT use sizeof()
726    to determine the offset or location.
727 
728    Concepts: binary files^seeking
729    Concepts: files^seeking in binary
730 
731 .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(),
732           PetscBinarySynchronizedSeek()
733 @*/
734 PetscErrorCode  PetscBinarySynchronizedSeek(MPI_Comm comm,int fd,off_t off,PetscBinarySeekType whence,off_t *offset)
735 {
736   PetscErrorCode ierr;
737   PetscMPIInt    rank;
738 
739   PetscFunctionBegin;
740   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
741   if (!rank) {
742     ierr = PetscBinarySeek(fd,off,whence,offset);CHKERRQ(ierr);
743   }
744   PetscFunctionReturn(0);
745 }
746 
747 #if defined(PETSC_HAVE_MPIIO)
748 #if !defined(PETSC_WORDS_BIGENDIAN)
749 
750 #if defined(PETSC_USE_PETSC_MPI_EXTERNAL32)
751 EXTERN_C_BEGIN
752 /*
753       MPICH does not provide the external32 representation for MPI_File_set_view() so we need to provide the functions.
754     These are set into MPI in PetscInitialize() via MPI_Register_datarep()
755 
756     Note I use PetscMPIInt for the MPI error codes since that is what MPI uses (instead of the standard PetscErrorCode)
757 
758     The next three routines are not used because MPICH does not support their use
759 
760 */
761 PetscMPIInt PetscDataRep_extent_fn(MPI_Datatype datatype,MPI_Aint *file_extent,void *extra_state)
762 {
763   MPI_Aint    ub;
764   PetscMPIInt ierr;
765 
766   ierr = MPI_Type_get_extent(datatype,&ub,file_extent);
767   return ierr;
768 }
769 
770 PetscMPIInt PetscDataRep_read_conv_fn(void *userbuf, MPI_Datatype datatype,PetscMPIInt count,void *filebuf, MPI_Offset position,void *extra_state)
771 {
772   PetscDataType pdtype;
773   PetscMPIInt   ierr;
774   size_t        dsize;
775 
776   ierr = PetscMPIDataTypeToPetscDataType(datatype,&pdtype);CHKERRQ(ierr);
777   ierr = PetscDataTypeGetSize(pdtype,&dsize);CHKERRQ(ierr);
778 
779   /* offset is given in units of MPI_Datatype */
780   userbuf = ((char *)userbuf) + dsize*position;
781 
782   ierr = PetscMemcpy(userbuf,filebuf,count*dsize);CHKERRQ(ierr);
783   ierr = PetscByteSwap(userbuf,pdtype,count);CHKERRQ(ierr);
784   return ierr;
785 }
786 
787 PetscMPIInt PetscDataRep_write_conv_fn(void *userbuf, MPI_Datatype datatype,PetscMPIInt count,void *filebuf, MPI_Offset position,void *extra_state)
788 {
789   PetscDataType pdtype;
790   PetscMPIInt   ierr;
791   size_t        dsize;
792 
793   ierr = PetscMPIDataTypeToPetscDataType(datatype,&pdtype);CHKERRQ(ierr);
794   ierr = PetscDataTypeGetSize(pdtype,&dsize);CHKERRQ(ierr);
795 
796   /* offset is given in units of MPI_Datatype */
797   userbuf = ((char *)userbuf) + dsize*position;
798 
799   ierr = PetscMemcpy(filebuf,userbuf,count*dsize);CHKERRQ(ierr);
800   ierr = PetscByteSwap(filebuf,pdtype,count);CHKERRQ(ierr);
801   return ierr;
802 }
803 EXTERN_C_END
804 #endif
805 
806 #undef __FUNCT__
807 #define __FUNCT__ "MPIU_File_write_all"
808 PetscErrorCode MPIU_File_write_all(MPI_File fd,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
809 {
810   PetscErrorCode ierr;
811   PetscDataType  pdtype;
812 
813   PetscFunctionBegin;
814   ierr = PetscMPIDataTypeToPetscDataType(dtype,&pdtype);CHKERRQ(ierr);
815   ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);
816   ierr = MPI_File_write_all(fd,data,cnt,dtype,status);CHKERRQ(ierr);
817   ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);
818   PetscFunctionReturn(0);
819 }
820 
821 #undef __FUNCT__
822 #define __FUNCT__ "MPIU_File_read_all"
823 PetscErrorCode MPIU_File_read_all(MPI_File fd,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
824 {
825   PetscErrorCode ierr;
826   PetscDataType  pdtype;
827 
828   PetscFunctionBegin;
829   ierr = PetscMPIDataTypeToPetscDataType(dtype,&pdtype);CHKERRQ(ierr);
830   ierr = MPI_File_read_all(fd,data,cnt,dtype,status);CHKERRQ(ierr);
831   ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);
832   PetscFunctionReturn(0);
833 }
834 #endif
835 #endif
836