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