xref: /petsc/src/sys/fileio/sysio.c (revision 8cbdbec6f8317ddf7886f91eb9c6bd083b543c50)
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 {
570     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Unknown seek location");
571   }
572 #if defined(PETSC_HAVE_LSEEK)
573   *offset = lseek(fd,off,iwhence);
574 #elif defined(PETSC_HAVE__LSEEK)
575   *offset = _lseek(fd,(long)off,iwhence);
576 #else
577   SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP_SYS,"System does not have a way of seeking on a file");
578 #endif
579   PetscFunctionReturn(0);
580 }
581 
582 #undef __FUNCT__
583 #define __FUNCT__ "PetscBinarySynchronizedRead"
584 /*@C
585    PetscBinarySynchronizedRead - Reads from a binary file.
586 
587    Collective on MPI_Comm
588 
589    Input Parameters:
590 +  comm - the MPI communicator
591 .  fd - the file
592 .  n  - the number of items to read
593 -  type - the type of items to read (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)
594 
595    Output Parameters:
596 .  p - the buffer
597 
598    Options Database Key:
599 .   -binary_longints - indicates the file was generated on a Cray vector
600          machine (not the T3E/D) and the ints are stored as 64 bit
601          quantities, otherwise they are stored as 32 bit
602 
603    Level: developer
604 
605    Notes:
606    Does a PetscBinaryRead() followed by an MPI_Bcast()
607 
608    PetscBinarySynchronizedRead() uses byte swapping to work on all machines.
609    Integers are stored on the file as 32 long, regardless of whether
610    they are stored in the machine as 32 or 64, this means the same
611    binary file may be read on any machine.
612 
613    Concepts: files^synchronized reading of binary files
614    Concepts: binary files^reading, synchronized
615 
616 .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead(), PetscBinarySynchronizedWrite(),
617           PetscBinarySynchronizedSeek()
618 @*/
619 PetscErrorCode  PetscBinarySynchronizedRead(MPI_Comm comm,int fd,void *p,PetscInt n,PetscDataType type)
620 {
621   PetscErrorCode ierr;
622   PetscMPIInt    rank;
623   MPI_Datatype   mtype;
624   char           *fname;
625   PetscBool      functionload = PETSC_FALSE;
626   void           *ptmp;
627 
628   PetscFunctionBegin;
629   if (type == PETSC_FUNCTION) {
630     functionload = PETSC_TRUE;
631     n            = 64;
632     type         = PETSC_CHAR;
633     ptmp         = p;
634     /* warning memory leak */
635     fname        = (char*)malloc(64*sizeof(char));
636     p            = (void*)fname;
637   }
638 
639   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
640   if (!rank) {
641     ierr = PetscBinaryRead(fd,p,n,type);CHKERRQ(ierr);
642   }
643   ierr = PetscDataTypeToMPIDataType(type,&mtype);CHKERRQ(ierr);
644   ierr = MPI_Bcast(p,n,mtype,0,comm);CHKERRQ(ierr);
645 
646   if (functionload) {
647 #if defined(PETSC_SERIALIZE_FUNCTIONS)
648     ierr = PetscDLLibrarySym(PETSC_COMM_SELF,&PetscDLLibrariesLoaded,PETSC_NULL,fname,(void**)ptmp);CHKERRQ(ierr);
649 #else
650     *(void**)ptmp = PETSC_NULL;
651 #endif
652   }
653   PetscFunctionReturn(0);
654 }
655 
656 #undef __FUNCT__
657 #define __FUNCT__ "PetscBinarySynchronizedWrite"
658 /*@C
659    PetscBinarySynchronizedWrite - writes to a binary file.
660 
661    Collective on MPI_Comm
662 
663    Input Parameters:
664 +  comm - the MPI communicator
665 .  fd - the file
666 .  n  - the number of items to write
667 .  p - the buffer
668 .  istemp - the buffer may be changed
669 -  type - the type of items to write (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)
670 
671    Level: developer
672 
673    Notes:
674    Process 0 does a PetscBinaryWrite()
675 
676    PetscBinarySynchronizedWrite() uses byte swapping to work on all machines.
677    Integers are stored on the file as 32 long, regardless of whether
678    they are stored in the machine as 32 or 64, this means the same
679    binary file may be read on any machine.
680 
681    Notes: because byte-swapping may be done on the values in data it cannot be declared const
682 
683    WARNING: This is NOT like PetscSynchronizedFPrintf()! This routine ignores calls on all but process 0,
684    while PetscSynchronizedFPrintf() has all processes print their strings in order.
685 
686    Concepts: files^synchronized writing of binary files
687    Concepts: binary files^reading, synchronized
688 
689 .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead(), PetscBinarySynchronizedRead(),
690           PetscBinarySynchronizedSeek()
691 @*/
692 PetscErrorCode  PetscBinarySynchronizedWrite(MPI_Comm comm,int fd,void *p,PetscInt n,PetscDataType type,PetscBool  istemp)
693 {
694   PetscErrorCode ierr;
695   PetscMPIInt    rank;
696 
697   PetscFunctionBegin;
698   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
699   if (!rank) {
700     ierr = PetscBinaryWrite(fd,p,n,type,istemp);CHKERRQ(ierr);
701   }
702   PetscFunctionReturn(0);
703 }
704 
705 #undef __FUNCT__
706 #define __FUNCT__ "PetscBinarySynchronizedSeek"
707 /*@C
708    PetscBinarySynchronizedSeek - Moves the file pointer on a PETSc binary file.
709 
710 
711    Input Parameters:
712 +  fd - the file
713 .  whence - if PETSC_BINARY_SEEK_SET then size is an absolute location in the file
714             if PETSC_BINARY_SEEK_CUR then size is offset from current location
715             if PETSC_BINARY_SEEK_END then size is offset from end of file
716 -  off    - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE,
717             etc. in your calculation rather than sizeof() to compute byte lengths.
718 
719    Output Parameter:
720 .   offset - new offset in file
721 
722    Level: developer
723 
724    Notes:
725    Integers are stored on the file as 32 long, regardless of whether
726    they are stored in the machine as 32 or 64, this means the same
727    binary file may be read on any machine. Hence you CANNOT use sizeof()
728    to determine the offset or location.
729 
730    Concepts: binary files^seeking
731    Concepts: files^seeking in binary
732 
733 .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(),
734           PetscBinarySynchronizedSeek()
735 @*/
736 PetscErrorCode  PetscBinarySynchronizedSeek(MPI_Comm comm,int fd,off_t off,PetscBinarySeekType whence,off_t *offset)
737 {
738   PetscErrorCode ierr;
739   PetscMPIInt    rank;
740 
741   PetscFunctionBegin;
742   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
743   if (!rank) {
744     ierr = PetscBinarySeek(fd,off,whence,offset);CHKERRQ(ierr);
745   }
746   PetscFunctionReturn(0);
747 }
748 
749 #if defined(PETSC_HAVE_MPIIO)
750 #if !defined(PETSC_WORDS_BIGENDIAN)
751 
752 #if defined(PETSC_USE_PETSC_MPI_EXTERNAL32)
753 EXTERN_C_BEGIN
754 /*
755       MPICH does not provide the external32 representation for MPI_File_set_view() so we need to provide the functions.
756     These are set into MPI in PetscInitialize() via MPI_Register_datarep()
757 
758     Note I use PetscMPIInt for the MPI error codes since that is what MPI uses (instead of the standard PetscErrorCode)
759 
760     The next three routines are not used because MPICH does not support their use
761 
762 */
763 PetscMPIInt PetscDataRep_extent_fn(MPI_Datatype datatype,MPI_Aint *file_extent,void *extra_state)
764 {
765   MPI_Aint    ub;
766   PetscMPIInt ierr;
767 
768   ierr = MPI_Type_get_extent(datatype,&ub,file_extent);
769   return ierr;
770 }
771 
772 PetscMPIInt PetscDataRep_read_conv_fn(void *userbuf, MPI_Datatype datatype,PetscMPIInt count,void *filebuf, MPI_Offset position,void *extra_state)
773 {
774   PetscDataType pdtype;
775   PetscMPIInt   ierr;
776   size_t        dsize;
777 
778   ierr = PetscMPIDataTypeToPetscDataType(datatype,&pdtype);CHKERRQ(ierr);
779   ierr = PetscDataTypeGetSize(pdtype,&dsize);CHKERRQ(ierr);
780 
781   /* offset is given in units of MPI_Datatype */
782   userbuf = ((char *)userbuf) + dsize*position;
783 
784   ierr = PetscMemcpy(userbuf,filebuf,count*dsize);CHKERRQ(ierr);
785   ierr = PetscByteSwap(userbuf,pdtype,count);CHKERRQ(ierr);
786   return ierr;
787 }
788 
789 PetscMPIInt PetscDataRep_write_conv_fn(void *userbuf, MPI_Datatype datatype,PetscMPIInt count,void *filebuf, MPI_Offset position,void *extra_state)
790 {
791   PetscDataType pdtype;
792   PetscMPIInt   ierr;
793   size_t        dsize;
794 
795   ierr = PetscMPIDataTypeToPetscDataType(datatype,&pdtype);CHKERRQ(ierr);
796   ierr = PetscDataTypeGetSize(pdtype,&dsize);CHKERRQ(ierr);
797 
798   /* offset is given in units of MPI_Datatype */
799   userbuf = ((char *)userbuf) + dsize*position;
800 
801   ierr = PetscMemcpy(filebuf,userbuf,count*dsize);CHKERRQ(ierr);
802   ierr = PetscByteSwap(filebuf,pdtype,count);CHKERRQ(ierr);
803   return ierr;
804 }
805 EXTERN_C_END
806 #endif
807 
808 #undef __FUNCT__
809 #define __FUNCT__ "MPIU_File_write_all"
810 PetscErrorCode MPIU_File_write_all(MPI_File fd,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
811 {
812   PetscErrorCode ierr;
813   PetscDataType  pdtype;
814 
815   PetscFunctionBegin;
816   ierr = PetscMPIDataTypeToPetscDataType(dtype,&pdtype);CHKERRQ(ierr);
817   ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);
818   ierr = MPI_File_write_all(fd,data,cnt,dtype,status);CHKERRQ(ierr);
819   ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);
820   PetscFunctionReturn(0);
821 }
822 
823 #undef __FUNCT__
824 #define __FUNCT__ "MPIU_File_read_all"
825 PetscErrorCode MPIU_File_read_all(MPI_File fd,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
826 {
827   PetscErrorCode ierr;
828   PetscDataType  pdtype;
829 
830   PetscFunctionBegin;
831   ierr = PetscMPIDataTypeToPetscDataType(dtype,&pdtype);CHKERRQ(ierr);
832   ierr = MPI_File_read_all(fd,data,cnt,dtype,status);CHKERRQ(ierr);
833   ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);
834   PetscFunctionReturn(0);
835 }
836 #endif
837 #endif
838