1 
2 /*
3    This file contains simple binary read/write routines.
4  */
5 
6 #include <petscsys.h>
7 #include <petscbt.h>
8 #include <errno.h>
9 #include <fcntl.h>
10 #if defined(PETSC_HAVE_UNISTD_H)
11 #include <unistd.h>
12 #endif
13 #if defined(PETSC_HAVE_IO_H)
14 #include <io.h>
15 #endif
16 #if !defined(PETSC_HAVE_O_BINARY)
17 #define O_BINARY 0
18 #endif
19 
20 const char *const PetscFileModes[] = {"READ","WRITE","APPEND","UPDATE","APPEND_UPDATE","PetscFileMode","PETSC_FILE_",NULL};
21 
22 /* --------------------------------------------------------- */
23 /*
24   PetscByteSwapEnum - Swap bytes in a  PETSc Enum
25 
26 */
PetscByteSwapEnum(PetscEnum * buff,PetscInt n)27 PetscErrorCode  PetscByteSwapEnum(PetscEnum *buff,PetscInt n)
28 {
29   PetscInt  i,j;
30   PetscEnum tmp = ENUM_DUMMY;
31   char      *ptr1,*ptr2 = (char*)&tmp;
32 
33   PetscFunctionBegin;
34   for (j=0; j<n; j++) {
35     ptr1 = (char*)(buff + j);
36     for (i=0; i<(PetscInt)sizeof(PetscEnum); i++) ptr2[i] = ptr1[sizeof(PetscEnum)-1-i];
37     for (i=0; i<(PetscInt)sizeof(PetscEnum); i++) ptr1[i] = ptr2[i];
38   }
39   PetscFunctionReturn(0);
40 }
41 
42 /*
43   PetscByteSwapBool - Swap bytes in a  PETSc Bool
44 
45 */
PetscByteSwapBool(PetscBool * buff,PetscInt n)46 PetscErrorCode  PetscByteSwapBool(PetscBool *buff,PetscInt n)
47 {
48   PetscInt  i,j;
49   PetscBool tmp = PETSC_FALSE;
50   char      *ptr1,*ptr2 = (char*)&tmp;
51 
52   PetscFunctionBegin;
53   for (j=0; j<n; j++) {
54     ptr1 = (char*)(buff + j);
55     for (i=0; i<(PetscInt)sizeof(PetscBool); i++) ptr2[i] = ptr1[sizeof(PetscBool)-1-i];
56     for (i=0; i<(PetscInt)sizeof(PetscBool); i++) ptr1[i] = ptr2[i];
57   }
58   PetscFunctionReturn(0);
59 }
60 
61 /*
62   PetscByteSwapInt - Swap bytes in a  PETSc integer (which may be 32 or 64 bits)
63 
64 */
PetscByteSwapInt(PetscInt * buff,PetscInt n)65 PetscErrorCode  PetscByteSwapInt(PetscInt *buff,PetscInt n)
66 {
67   PetscInt i,j,tmp = 0;
68   char     *ptr1,*ptr2 = (char*)&tmp;
69 
70   PetscFunctionBegin;
71   for (j=0; j<n; j++) {
72     ptr1 = (char*)(buff + j);
73     for (i=0; i<(PetscInt)sizeof(PetscInt); i++) ptr2[i] = ptr1[sizeof(PetscInt)-1-i];
74     for (i=0; i<(PetscInt)sizeof(PetscInt); i++) ptr1[i] = ptr2[i];
75   }
76   PetscFunctionReturn(0);
77 }
78 
79 /*
80   PetscByteSwapInt64 - Swap bytes in a  PETSc integer (64 bits)
81 
82 */
PetscByteSwapInt64(PetscInt64 * buff,PetscInt n)83 PetscErrorCode  PetscByteSwapInt64(PetscInt64 *buff,PetscInt n)
84 {
85   PetscInt   i,j;
86   PetscInt64 tmp = 0;
87   char       *ptr1,*ptr2 = (char*)&tmp;
88 
89   PetscFunctionBegin;
90   for (j=0; j<n; j++) {
91     ptr1 = (char*)(buff + j);
92     for (i=0; i<(PetscInt)sizeof(PetscInt64); i++) ptr2[i] = ptr1[sizeof(PetscInt64)-1-i];
93     for (i=0; i<(PetscInt)sizeof(PetscInt64); i++) ptr1[i] = ptr2[i];
94   }
95   PetscFunctionReturn(0);
96 }
97 
98 /* --------------------------------------------------------- */
99 /*
100   PetscByteSwapShort - Swap bytes in a short
101 */
PetscByteSwapShort(short * buff,PetscInt n)102 PetscErrorCode  PetscByteSwapShort(short *buff,PetscInt n)
103 {
104   PetscInt i,j;
105   short    tmp;
106   char     *ptr1,*ptr2 = (char*)&tmp;
107 
108   PetscFunctionBegin;
109   for (j=0; j<n; j++) {
110     ptr1 = (char*)(buff + j);
111     for (i=0; i<(PetscInt) sizeof(short); i++) ptr2[i] = ptr1[sizeof(short)-1-i];
112     for (i=0; i<(PetscInt) sizeof(short); i++) ptr1[i] = ptr2[i];
113   }
114   PetscFunctionReturn(0);
115 }
116 /*
117   PetscByteSwapLong - Swap bytes in a long
118 */
PetscByteSwapLong(long * buff,PetscInt n)119 PetscErrorCode  PetscByteSwapLong(long *buff,PetscInt n)
120 {
121   PetscInt i,j;
122   long     tmp;
123   char     *ptr1,*ptr2 = (char*)&tmp;
124 
125   PetscFunctionBegin;
126   for (j=0; j<n; j++) {
127     ptr1 = (char*)(buff + j);
128     for (i=0; i<(PetscInt) sizeof(long); i++) ptr2[i] = ptr1[sizeof(long)-1-i];
129     for (i=0; i<(PetscInt) sizeof(long); i++) ptr1[i] = ptr2[i];
130   }
131   PetscFunctionReturn(0);
132 }
133 /* --------------------------------------------------------- */
134 /*
135   PetscByteSwapReal - Swap bytes in a PetscReal
136 */
PetscByteSwapReal(PetscReal * buff,PetscInt n)137 PetscErrorCode  PetscByteSwapReal(PetscReal *buff,PetscInt n)
138 {
139   PetscInt  i,j;
140   PetscReal tmp,*buff1 = (PetscReal*)buff;
141   char      *ptr1,*ptr2 = (char*)&tmp;
142 
143   PetscFunctionBegin;
144   for (j=0; j<n; j++) {
145     ptr1 = (char*)(buff1 + j);
146     for (i=0; i<(PetscInt) sizeof(PetscReal); i++) ptr2[i] = ptr1[sizeof(PetscReal)-1-i];
147     for (i=0; i<(PetscInt) sizeof(PetscReal); i++) ptr1[i] = ptr2[i];
148   }
149   PetscFunctionReturn(0);
150 }
151 /* --------------------------------------------------------- */
152 /*
153   PetscByteSwapScalar - Swap bytes in a PetscScalar
154   The complex case is dealt with with an array of PetscReal, twice as long.
155 */
PetscByteSwapScalar(PetscScalar * buff,PetscInt n)156 PetscErrorCode  PetscByteSwapScalar(PetscScalar *buff,PetscInt n)
157 {
158   PetscInt  i,j;
159   PetscReal tmp,*buff1 = (PetscReal*)buff;
160   char      *ptr1,*ptr2 = (char*)&tmp;
161 
162   PetscFunctionBegin;
163 #if defined(PETSC_USE_COMPLEX)
164   n *= 2;
165 #endif
166   for (j=0; j<n; j++) {
167     ptr1 = (char*)(buff1 + j);
168     for (i=0; i<(PetscInt) sizeof(PetscReal); i++) ptr2[i] = ptr1[sizeof(PetscReal)-1-i];
169     for (i=0; i<(PetscInt) sizeof(PetscReal); i++) ptr1[i] = ptr2[i];
170   }
171   PetscFunctionReturn(0);
172 }
173 /* --------------------------------------------------------- */
174 /*
175   PetscByteSwapDouble - Swap bytes in a double
176 */
PetscByteSwapDouble(double * buff,PetscInt n)177 PetscErrorCode  PetscByteSwapDouble(double *buff,PetscInt n)
178 {
179   PetscInt i,j;
180   double   tmp,*buff1 = (double*)buff;
181   char     *ptr1,*ptr2 = (char*)&tmp;
182 
183   PetscFunctionBegin;
184   for (j=0; j<n; j++) {
185     ptr1 = (char*)(buff1 + j);
186     for (i=0; i<(PetscInt) sizeof(double); i++) ptr2[i] = ptr1[sizeof(double)-1-i];
187     for (i=0; i<(PetscInt) sizeof(double); i++) ptr1[i] = ptr2[i];
188   }
189   PetscFunctionReturn(0);
190 }
191 
192 /*
193   PetscByteSwapFloat - Swap bytes in a float
194 */
PetscByteSwapFloat(float * buff,PetscInt n)195 PetscErrorCode PetscByteSwapFloat(float *buff,PetscInt n)
196 {
197   PetscInt i,j;
198   float    tmp,*buff1 = (float*)buff;
199   char     *ptr1,*ptr2 = (char*)&tmp;
200 
201   PetscFunctionBegin;
202   for (j=0; j<n; j++) {
203     ptr1 = (char*)(buff1 + j);
204     for (i=0; i<(PetscInt) sizeof(float); i++) ptr2[i] = ptr1[sizeof(float)-1-i];
205     for (i=0; i<(PetscInt) sizeof(float); i++) ptr1[i] = ptr2[i];
206   }
207   PetscFunctionReturn(0);
208 }
209 
PetscByteSwap(void * data,PetscDataType pdtype,PetscInt count)210 PetscErrorCode PetscByteSwap(void *data,PetscDataType pdtype,PetscInt count)
211 {
212   PetscErrorCode ierr;
213 
214   PetscFunctionBegin;
215   if      (pdtype == PETSC_INT)    {ierr = PetscByteSwapInt((PetscInt*)data,count);CHKERRQ(ierr);}
216   else if (pdtype == PETSC_ENUM)   {ierr = PetscByteSwapEnum((PetscEnum*)data,count);CHKERRQ(ierr);}
217   else if (pdtype == PETSC_BOOL)   {ierr = PetscByteSwapBool((PetscBool*)data,count);CHKERRQ(ierr);}
218   else if (pdtype == PETSC_SCALAR) {ierr = PetscByteSwapScalar((PetscScalar*)data,count);CHKERRQ(ierr);}
219   else if (pdtype == PETSC_REAL)   {ierr = PetscByteSwapReal((PetscReal*)data,count);CHKERRQ(ierr);}
220   else if (pdtype == PETSC_COMPLEX){ierr = PetscByteSwapReal((PetscReal*)data,2*count);CHKERRQ(ierr);}
221   else if (pdtype == PETSC_INT64)  {ierr = PetscByteSwapInt64((PetscInt64*)data,count);CHKERRQ(ierr);}
222   else if (pdtype == PETSC_DOUBLE) {ierr = PetscByteSwapDouble((double*)data,count);CHKERRQ(ierr);}
223   else if (pdtype == PETSC_FLOAT)  {ierr = PetscByteSwapFloat((float*)data,count);CHKERRQ(ierr);}
224   else if (pdtype == PETSC_SHORT)  {ierr = PetscByteSwapShort((short*)data,count);CHKERRQ(ierr);}
225   else if (pdtype == PETSC_LONG)   {ierr = PetscByteSwapLong((long*)data,count);CHKERRQ(ierr);}
226   PetscFunctionReturn(0);
227 }
228 
229 /*@C
230    PetscBinaryRead - Reads from a binary file.
231 
232    Not Collective
233 
234    Input Parameters:
235 +  fd - the file descriptor
236 .  num  - the maximum number of items to read
237 -  type - the type of items to read (PETSC_INT, PETSC_REAL, PETSC_SCALAR, etc.)
238 
239    Output Parameters:
240 +  data - the buffer
241 -  count - the number of items read, optional
242 
243    Level: developer
244 
245    Notes:
246    If count is not provided and the number of items read is less than
247    the maximum number of items to read, then this routine errors.
248 
249    PetscBinaryRead() uses byte swapping to work on all machines; the files
250    are written to file ALWAYS using big-endian ordering. On little-endian machines the numbers
251    are converted to the little-endian format when they are read in from the file.
252    When PETSc is ./configure with --with-64-bit-indices the integers are written to the
253    file as 64 bit integers, this means they can only be read back in when the option --with-64-bit-indices
254    is used.
255 
256 .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscViewerBinaryGetDescriptor(), PetscBinarySynchronizedWrite(),
257           PetscBinarySynchronizedRead(), PetscBinarySynchronizedSeek()
258 @*/
PetscBinaryRead(int fd,void * data,PetscInt num,PetscInt * count,PetscDataType type)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 
351    Level: advanced
352 
353    Notes:
354    PetscBinaryWrite() uses byte swapping to work on all machines; the files
355    are written using big-endian ordering to the file. On little-endian machines the numbers
356    are converted to the big-endian format when they are written to disk.
357    When PETSc is ./configure with --with-64-bit-indices the integers are written to the
358    file as 64 bit integers, this means they can only be read back in when the option --with-64-bit-indices
359    is used.
360 
361    If running with __float128 precision the output is in __float128 unless one uses the -binary_write_double option
362 
363    The Buffer p should be read-write buffer, and not static data.
364    This way, byte-swapping is done in-place, and then the buffer is
365    written to the file.
366 
367    This routine restores the original contents of the buffer, after
368    it is written to the file. This is done by byte-swapping in-place
369    the second time.
370 
371    Because byte-swapping may be done on the values in data it cannot be declared const
372 
373 
374 .seealso: PetscBinaryRead(), PetscBinaryOpen(), PetscBinaryClose(), PetscViewerBinaryGetDescriptor(), PetscBinarySynchronizedWrite(),
375           PetscBinarySynchronizedRead(), PetscBinarySynchronizedSeek()
376 @*/
PetscBinaryWrite(int fd,const void * p,PetscInt n,PetscDataType type)377 PetscErrorCode  PetscBinaryWrite(int fd,const void *p,PetscInt n,PetscDataType type)
378 {
379   const char     *pp = (char*)p;
380   int            err,wsize;
381   size_t         m = (size_t)n,maxblock=65536;
382   PetscErrorCode ierr;
383   const void     *ptmp = p;
384   char           *fname = NULL;
385 #if defined(PETSC_USE_REAL___FLOAT128)
386   PetscBool      writedouble = PETSC_FALSE;
387   double         *ppp;
388   PetscReal      *pv;
389   PetscInt       i;
390 #endif
391   PetscDataType  wtype = type;
392 
393   PetscFunctionBegin;
394   if (n < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Trying to write a negative amount of data %D",n);
395   if (!n) PetscFunctionReturn(0);
396 
397   if (type == PETSC_FUNCTION) {
398 #if defined(PETSC_SERIALIZE_FUNCTIONS)
399     const char *fnametmp;
400 #endif
401     m     = 64;
402     fname = (char*)malloc(m*sizeof(char));
403     if (!fname) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Cannot allocate space for function name");
404 #if defined(PETSC_SERIALIZE_FUNCTIONS)
405     if (n > 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Can only binary view a single function at a time");
406     ierr = PetscFPTFind(*(void**)p,&fnametmp);CHKERRQ(ierr);
407     ierr = PetscStrncpy(fname,fnametmp,m);CHKERRQ(ierr);
408 #else
409     ierr = PetscStrncpy(fname,"",m);CHKERRQ(ierr);
410 #endif
411     wtype = PETSC_CHAR;
412     pp    = (char*)fname;
413     ptmp  = (void*)fname;
414   }
415 
416 #if defined(PETSC_USE_REAL___FLOAT128)
417   ierr = PetscOptionsGetBool(NULL,NULL,"-binary_write_double",&writedouble,NULL);CHKERRQ(ierr);
418   /* If using __float128 precision we still write in doubles to file */
419   if ((type == PETSC_SCALAR || type == PETSC_REAL || type == PETSC_COMPLEX) && writedouble) {
420     wtype = PETSC_DOUBLE;
421     ierr = PetscMalloc1(n,&ppp);CHKERRQ(ierr);
422     pv = (PetscReal*)pp;
423     for (i=0; i<n; i++) {
424       ppp[i] = (double) pv[i];
425     }
426     pp   = (char*)ppp;
427     ptmp = (char*)ppp;
428   }
429 #endif
430 
431   if (wtype == PETSC_INT)          m *= sizeof(PetscInt);
432   else if (wtype == PETSC_SCALAR)  m *= sizeof(PetscScalar);
433 #if defined(PETSC_HAVE_COMPLEX)
434   else if (wtype == PETSC_COMPLEX) m *= sizeof(PetscComplex);
435 #endif
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((void*)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 (!PetscBinaryBigEndian()) {ierr = PetscByteSwap((void*)ptmp,wtype,n);CHKERRQ(ierr);}
460 
461   if (type == PETSC_FUNCTION) {
462     free(fname);
463   }
464 #if defined(PETSC_USE_REAL___FLOAT128)
465   if ((type == PETSC_SCALAR || type == PETSC_REAL || type == PETSC_COMPLEX) && writedouble) {
466     ierr = PetscFree(ppp);CHKERRQ(ierr);
467   }
468 #endif
469   PetscFunctionReturn(0);
470 }
471 
472 /*@C
473    PetscBinaryOpen - Opens a PETSc binary file.
474 
475    Not Collective
476 
477    Input Parameters:
478 +  name - filename
479 -  mode - open mode of binary file, one of FILE_MODE_READ, FILE_MODE_WRITE, FILE_MODE_APPEND
480 
481    Output Parameter:
482 .  fd - the file
483 
484    Level: advanced
485 
486 
487    Notes:
488     Files access with PetscBinaryRead() and PetscBinaryWrite() are ALWAYS written in
489    big-endian format. This means the file can be accessed using PetscBinaryOpen() and
490    PetscBinaryRead() and PetscBinaryWrite() on any machine.
491 
492 .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscFileMode, PetscViewerFileSetMode(), PetscViewerBinaryGetDescriptor(),
493           PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(), PetscBinarySynchronizedSeek()
494 
495 @*/
PetscBinaryOpen(const char name[],PetscFileMode mode,int * fd)496 PetscErrorCode  PetscBinaryOpen(const char name[],PetscFileMode mode,int *fd)
497 {
498   PetscFunctionBegin;
499   switch (mode) {
500   case FILE_MODE_READ:   *fd = open(name,O_BINARY|O_RDONLY,0); break;
501   case FILE_MODE_WRITE:  *fd = open(name,O_BINARY|O_WRONLY|O_CREAT|O_TRUNC,0666); break;
502   case FILE_MODE_APPEND: *fd = open(name,O_BINARY|O_WRONLY|O_APPEND,0); break;
503   default: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Unsupported file mode %s",PetscFileModes[mode]);
504   }
505   if (*fd == -1) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot open file %s for %s: %s",name,PetscFileModes[mode]);
506   PetscFunctionReturn(0);
507 }
508 
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 @*/
PetscBinaryClose(int fd)522 PetscErrorCode  PetscBinaryClose(int fd)
523 {
524   PetscFunctionBegin;
525   if (close(fd)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"close() failed on file descriptor");
526   PetscFunctionReturn(0);
527 }
528 
529 
530 /*@C
531    PetscBinarySeek - Moves the file pointer on a PETSc binary file.
532 
533    Not Collective
534 
535    Input Parameters:
536 +  fd - the file
537 .  off - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE,
538             etc. in your calculation rather than sizeof() to compute byte lengths.
539 -  whence - if PETSC_BINARY_SEEK_SET then off is an absolute location in the file
540             if PETSC_BINARY_SEEK_CUR then off is an offset from the current location
541             if PETSC_BINARY_SEEK_END then off is an offset from the end of file
542 
543    Output Parameter:
544 .   offset - new offset in file
545 
546    Level: developer
547 
548    Notes:
549    Integers are stored on the file as 32 long, regardless of whether
550    they are stored in the machine as 32 or 64, this means the same
551    binary file may be read on any machine. Hence you CANNOT use sizeof()
552    to determine the offset or location.
553 
554 
555 .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(),
556           PetscBinarySynchronizedSeek()
557 @*/
PetscBinarySeek(int fd,off_t off,PetscBinarySeekType whence,off_t * offset)558 PetscErrorCode  PetscBinarySeek(int fd,off_t off,PetscBinarySeekType whence,off_t *offset)
559 {
560   int iwhence = 0;
561 
562   PetscFunctionBegin;
563   if (whence == PETSC_BINARY_SEEK_SET) iwhence = SEEK_SET;
564   else if (whence == PETSC_BINARY_SEEK_CUR) iwhence = SEEK_CUR;
565   else if (whence == PETSC_BINARY_SEEK_END) iwhence = SEEK_END;
566   else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Unknown seek location");
567 #if defined(PETSC_HAVE_LSEEK)
568   *offset = lseek(fd,off,iwhence);
569 #elif defined(PETSC_HAVE__LSEEK)
570   *offset = _lseek(fd,(long)off,iwhence);
571 #else
572   SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP_SYS,"System does not have a way of seeking on a file");
573 #endif
574   PetscFunctionReturn(0);
575 }
576 
577 /*@C
578    PetscBinarySynchronizedRead - Reads from a binary file.
579 
580    Collective
581 
582    Input Parameters:
583 +  comm - the MPI communicator
584 .  fd - the file descriptor
585 .  num  - the maximum number of items to read
586 -  type - the type of items to read (PETSC_INT, PETSC_REAL, PETSC_SCALAR, etc.)
587 
588    Output Parameters:
589 +  data - the buffer
590 -  count - the number of items read, optional
591 
592    Level: developer
593 
594    Notes:
595    Does a PetscBinaryRead() followed by an MPI_Bcast()
596 
597    If count is not provided and the number of items read is less than
598    the maximum number of items to read, then this routine errors.
599 
600    PetscBinarySynchronizedRead() uses byte swapping to work on all machines.
601    Integers are stored on the file as 32 long, regardless of whether
602    they are stored in the machine as 32 or 64, this means the same
603    binary file may be read on any machine.
604 
605 
606 .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead(), PetscBinarySynchronizedWrite(),
607           PetscBinarySynchronizedSeek()
608 @*/
PetscBinarySynchronizedRead(MPI_Comm comm,int fd,void * data,PetscInt num,PetscInt * count,PetscDataType type)609 PetscErrorCode  PetscBinarySynchronizedRead(MPI_Comm comm,int fd,void *data,PetscInt num,PetscInt *count,PetscDataType type)
610 {
611   PetscErrorCode ierr;
612   PetscMPIInt    rank;
613   MPI_Datatype   mtype;
614   PetscInt       ibuf[2] = {0, 0};
615   char           *fname = NULL;
616   void           *fptr = NULL;
617 
618   PetscFunctionBegin;
619   if (type == PETSC_FUNCTION) {
620     num   = 64;
621     type  = PETSC_CHAR;
622     fname = (char*)malloc(num*sizeof(char));
623     fptr  = data;
624     data  = (void*)fname;
625     if (!fname) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Cannot allocate space for function name");
626   }
627 
628   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
629   if (!rank) {
630     ibuf[0] = PetscBinaryRead(fd,data,num,count?&ibuf[1]:NULL,type);
631   }
632   ierr = MPI_Bcast(ibuf,2,MPIU_INT,0,comm);CHKERRQ(ierr);
633   ierr = (PetscErrorCode)ibuf[0];CHKERRQ(ierr);
634   ierr = PetscDataTypeToMPIDataType(type,&mtype);CHKERRQ(ierr);
635   ierr = MPI_Bcast(data,count?ibuf[1]:num,mtype,0,comm);CHKERRQ(ierr);
636   if (count) *count = ibuf[1];
637 
638   if (type == PETSC_FUNCTION) {
639 #if defined(PETSC_SERIALIZE_FUNCTIONS)
640     ierr = PetscDLLibrarySym(PETSC_COMM_SELF,&PetscDLLibrariesLoaded,NULL,fname,(void**)fptr);CHKERRQ(ierr);
641 #else
642     *(void**)fptr = NULL;
643 #endif
644     free(fname);
645   }
646   PetscFunctionReturn(0);
647 }
648 
649 /*@C
650    PetscBinarySynchronizedWrite - writes to a binary file.
651 
652    Collective
653 
654    Input Parameters:
655 +  comm - the MPI communicator
656 .  fd - the file
657 .  n  - the number of items to write
658 .  p - the buffer
659 -  type - the type of items to write (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)
660 
661    Level: developer
662 
663    Notes:
664    Process 0 does a PetscBinaryWrite()
665 
666    PetscBinarySynchronizedWrite() uses byte swapping to work on all machines.
667    Integers are stored on the file as 32 long, regardless of whether
668    they are stored in the machine as 32 or 64, this means the same
669    binary file may be read on any machine.
670 
671    Notes:
672     because byte-swapping may be done on the values in data it cannot be declared const
673 
674    WARNING: This is NOT like PetscSynchronizedFPrintf()! This routine ignores calls on all but process 0,
675    while PetscSynchronizedFPrintf() has all processes print their strings in order.
676 
677 
678 .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead(), PetscBinarySynchronizedRead(),
679           PetscBinarySynchronizedSeek()
680 @*/
PetscBinarySynchronizedWrite(MPI_Comm comm,int fd,const void * p,PetscInt n,PetscDataType type)681 PetscErrorCode  PetscBinarySynchronizedWrite(MPI_Comm comm,int fd,const void *p,PetscInt n,PetscDataType type)
682 {
683   PetscErrorCode ierr;
684   PetscMPIInt    rank;
685 
686   PetscFunctionBegin;
687   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
688   if (!rank) {
689     ierr = PetscBinaryWrite(fd,p,n,type);CHKERRQ(ierr);
690   }
691   PetscFunctionReturn(0);
692 }
693 
694 /*@C
695    PetscBinarySynchronizedSeek - Moves the file pointer on a PETSc binary file.
696 
697 
698    Input Parameters:
699 +  fd - the file
700 .  whence - if PETSC_BINARY_SEEK_SET then size is an absolute location in the file
701             if PETSC_BINARY_SEEK_CUR then size is offset from current location
702             if PETSC_BINARY_SEEK_END then size is offset from end of file
703 -  off    - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE,
704             etc. in your calculation rather than sizeof() to compute byte lengths.
705 
706    Output Parameter:
707 .   offset - new offset in file
708 
709    Level: developer
710 
711    Notes:
712    Integers are stored on the file as 32 long, regardless of whether
713    they are stored in the machine as 32 or 64, this means the same
714    binary file may be read on any machine. Hence you CANNOT use sizeof()
715    to determine the offset or location.
716 
717 
718 .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(),
719           PetscBinarySynchronizedSeek()
720 @*/
PetscBinarySynchronizedSeek(MPI_Comm comm,int fd,off_t off,PetscBinarySeekType whence,off_t * offset)721 PetscErrorCode  PetscBinarySynchronizedSeek(MPI_Comm comm,int fd,off_t off,PetscBinarySeekType whence,off_t *offset)
722 {
723   PetscErrorCode ierr;
724   PetscMPIInt    rank;
725 
726   PetscFunctionBegin;
727   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
728   if (!rank) {
729     ierr = PetscBinarySeek(fd,off,whence,offset);CHKERRQ(ierr);
730   }
731   PetscFunctionReturn(0);
732 }
733 
734 #if defined(PETSC_HAVE_MPIIO)
735 
736 #if defined(PETSC_USE_PETSC_MPI_EXTERNAL32)
737 /*
738       MPICH does not provide the external32 representation for MPI_File_set_view() so we need to provide the functions.
739     These are set into MPI in PetscInitialize() via MPI_Register_datarep()
740 
741     Note I use PetscMPIInt for the MPI error codes since that is what MPI uses (instead of the standard PetscErrorCode)
742 
743     The next three routines are not used because MPICH does not support their use
744 
745 */
PetscDataRep_extent_fn(MPI_Datatype datatype,MPI_Aint * file_extent,void * extra_state)746 PETSC_EXTERN PetscMPIInt PetscDataRep_extent_fn(MPI_Datatype datatype,MPI_Aint *file_extent,void *extra_state)
747 {
748   MPI_Aint    ub;
749   PetscMPIInt ierr;
750 
751   ierr = MPI_Type_get_extent(datatype,&ub,file_extent);
752   return ierr;
753 }
754 
PetscDataRep_read_conv_fn(void * userbuf,MPI_Datatype datatype,PetscMPIInt count,void * filebuf,MPI_Offset position,void * extra_state)755 PETSC_EXTERN PetscMPIInt PetscDataRep_read_conv_fn(void *userbuf, MPI_Datatype datatype,PetscMPIInt count,void *filebuf, MPI_Offset position,void *extra_state)
756 {
757   PetscDataType pdtype;
758   PetscMPIInt   ierr;
759   size_t        dsize;
760 
761   ierr = PetscMPIDataTypeToPetscDataType(datatype,&pdtype);CHKERRQ(ierr);
762   ierr = PetscDataTypeGetSize(pdtype,&dsize);CHKERRQ(ierr);
763 
764   /* offset is given in units of MPI_Datatype */
765   userbuf = ((char*)userbuf) + dsize*position;
766 
767   ierr = PetscMemcpy(userbuf,filebuf,count*dsize);CHKERRQ(ierr);
768   if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(userbuf,pdtype,count);CHKERRQ(ierr);}
769   return ierr;
770 }
771 
PetscDataRep_write_conv_fn(void * userbuf,MPI_Datatype datatype,PetscMPIInt count,void * filebuf,MPI_Offset position,void * extra_state)772 PetscMPIInt PetscDataRep_write_conv_fn(void *userbuf, MPI_Datatype datatype,PetscMPIInt count,void *filebuf, MPI_Offset position,void *extra_state)
773 {
774   PetscDataType pdtype;
775   PetscMPIInt   ierr;
776   size_t        dsize;
777 
778   ierr = PetscMPIDataTypeToPetscDataType(datatype,&pdtype);CHKERRQ(ierr);
779   ierr = PetscDataTypeGetSize(pdtype,&dsize);CHKERRQ(ierr);
780 
781   /* offset is given in units of MPI_Datatype */
782   userbuf = ((char*)userbuf) + dsize*position;
783 
784   ierr = PetscMemcpy(filebuf,userbuf,count*dsize);CHKERRQ(ierr);
785   if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(filebuf,pdtype,count);CHKERRQ(ierr);}
786   return ierr;
787 }
788 #endif
789 
MPIU_File_write_all(MPI_File fd,void * data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status * status)790 PetscErrorCode MPIU_File_write_all(MPI_File fd,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
791 {
792   PetscDataType  pdtype;
793   PetscErrorCode ierr;
794 
795 
796   PetscFunctionBegin;
797   ierr = PetscMPIDataTypeToPetscDataType(dtype,&pdtype);CHKERRQ(ierr);
798   if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);}
799   ierr = MPI_File_write_all(fd,data,cnt,dtype,status);CHKERRQ(ierr);
800   if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);}
801   PetscFunctionReturn(0);
802 }
803 
MPIU_File_read_all(MPI_File fd,void * data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status * status)804 PetscErrorCode MPIU_File_read_all(MPI_File fd,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
805 {
806   PetscDataType  pdtype;
807   PetscErrorCode ierr;
808 
809   PetscFunctionBegin;
810   ierr = PetscMPIDataTypeToPetscDataType(dtype,&pdtype);CHKERRQ(ierr);
811   ierr = MPI_File_read_all(fd,data,cnt,dtype,status);CHKERRQ(ierr);
812   if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);}
813   PetscFunctionReturn(0);
814 }
815 
MPIU_File_write_at(MPI_File fd,MPI_Offset off,void * data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status * status)816 PetscErrorCode MPIU_File_write_at(MPI_File fd,MPI_Offset off,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_at(fd,off,data,cnt,dtype,status);CHKERRQ(ierr);
826   if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);}
827   PetscFunctionReturn(0);
828 }
829 
MPIU_File_read_at(MPI_File fd,MPI_Offset off,void * data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status * status)830 PetscErrorCode MPIU_File_read_at(MPI_File fd,MPI_Offset off,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_at(fd,off,data,cnt,dtype,status);CHKERRQ(ierr);
838   if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);}
839   PetscFunctionReturn(0);
840 }
841 
MPIU_File_write_at_all(MPI_File fd,MPI_Offset off,void * data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status * status)842 PetscErrorCode MPIU_File_write_at_all(MPI_File fd,MPI_Offset off,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
843 {
844   PetscDataType  pdtype;
845   PetscErrorCode ierr;
846 
847 
848   PetscFunctionBegin;
849   ierr = PetscMPIDataTypeToPetscDataType(dtype,&pdtype);CHKERRQ(ierr);
850   if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);}
851   ierr = MPI_File_write_at_all(fd,off,data,cnt,dtype,status);CHKERRQ(ierr);
852   if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);}
853   PetscFunctionReturn(0);
854 }
855 
MPIU_File_read_at_all(MPI_File fd,MPI_Offset off,void * data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status * status)856 PetscErrorCode MPIU_File_read_at_all(MPI_File fd,MPI_Offset off,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
857 {
858   PetscDataType  pdtype;
859   PetscErrorCode ierr;
860 
861   PetscFunctionBegin;
862   ierr = PetscMPIDataTypeToPetscDataType(dtype,&pdtype);CHKERRQ(ierr);
863   ierr = MPI_File_read_at_all(fd,off,data,cnt,dtype,status);CHKERRQ(ierr);
864   if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);}
865   PetscFunctionReturn(0);
866 }
867 
868 #endif
869