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