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