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