Actual source code: sysio.c

  1: #define PETSC_DLL

  3: /* 
  4:    This file contains simple binary read/write routines.
  5:  */

 7:  #include petsc.h
 8:  #include petscsys.h

 10: #include <errno.h>
 11: #include <fcntl.h>
 12: #if defined(PETSC_HAVE_UNISTD_H)
 13: #include <unistd.h>
 14: #endif
 15: #if defined (PETSC_HAVE_IO_H)
 16: #include <io.h>
 17: #endif
 18:  #include petscbt.h

 20: #if (PETSC_SIZEOF_INT == 8)
 21: #define PetscInt32 short
 22: #else
 23: #define PetscInt32 int
 24: #endif

 26: #if !defined(PETSC_WORDS_BIGENDIAN)

 30: /*
 31:   PetscByteSwapInt - Swap bytes in a 32 bit integer. NOT a PetscInt! Note that PETSc binary read and write
 32:       always store and read only 32 bit integers! (See PetscBinaryRead(), PetscBinaryWrite()).

 34: */
 35: PetscErrorCode  PetscByteSwapInt(PetscInt32 *buff,PetscInt n)
 36: {
 37:   PetscInt  i,j,tmp = 0;
 38:   PetscInt  *tptr = &tmp;                /* Need to access tmp indirectly to get */
 39:   char      *ptr1,*ptr2 = (char*)&tmp; /* arround the bug in DEC-ALPHA g++ */
 40: 
 42:   for (j=0; j<n; j++) {
 43:     ptr1 = (char*)(buff + j);
 44:     for (i=0; i<(int)sizeof(PetscInt32); i++) {
 45:       ptr2[i] = ptr1[sizeof(PetscInt32)-1-i];
 46:     }
 47:     buff[j] = *tptr;
 48:   }
 49:   return(0);
 50: }
 51: /* --------------------------------------------------------- */
 54: /*
 55:   PetscByteSwapShort - Swap bytes in a short
 56: */
 57: PetscErrorCode  PetscByteSwapShort(short *buff,PetscInt n)
 58: {
 59:   PetscInt   i,j;
 60:   short      tmp;
 61:   short      *tptr = &tmp;           /* take care pf bug in DEC-ALPHA g++ */
 62:   char       *ptr1,*ptr2 = (char*)&tmp;

 65:   for (j=0; j<n; j++) {
 66:     ptr1 = (char*)(buff + j);
 67:     for (i=0; i<(int) sizeof(short); i++) {
 68:       ptr2[i] = ptr1[sizeof(int)-1-i];
 69:     }
 70:     buff[j] = *tptr;
 71:   }
 72:   return(0);
 73: }
 74: /* --------------------------------------------------------- */
 77: /*
 78:   PetscByteSwapScalar - Swap bytes in a double
 79:   Complex is dealt with as if array of double twice as long.
 80: */
 81: PetscErrorCode  PetscByteSwapScalar(PetscScalar *buff,PetscInt n)
 82: {
 83:   PetscInt  i,j;
 84:   PetscReal tmp,*buff1 = (PetscReal*)buff;
 85:   PetscReal *tptr = &tmp;          /* take care pf bug in DEC-ALPHA g++ */
 86:   char      *ptr1,*ptr2 = (char*)&tmp;

 89: #if defined(PETSC_USE_COMPLEX)
 90:   n *= 2;
 91: #endif
 92:   for (j=0; j<n; j++) {
 93:     ptr1 = (char*)(buff1 + j);
 94:     for (i=0; i<(int) sizeof(PetscReal); i++) {
 95:       ptr2[i] = ptr1[sizeof(PetscReal)-1-i];
 96:     }
 97:     buff1[j] = *tptr;
 98:   }
 99:   return(0);
100: }
101: /* --------------------------------------------------------- */
104: /*
105:   PetscByteSwapDouble - Swap bytes in a double
106: */
107: PetscErrorCode  PetscByteSwapDouble(double *buff,PetscInt n)
108: {
109:   PetscInt i,j;
110:   double   tmp,*buff1 = (double*)buff;
111:   double   *tptr = &tmp;          /* take care pf bug in DEC-ALPHA g++ */
112:   char     *ptr1,*ptr2 = (char*)&tmp;

115:   for (j=0; j<n; j++) {
116:     ptr1 = (char*)(buff1 + j);
117:     for (i=0; i<(int) sizeof(double); i++) {
118:       ptr2[i] = ptr1[sizeof(double)-1-i];
119:     }
120:     buff1[j] = *tptr;
121:   }
122:   return(0);
123: }
124: #endif
125: /* --------------------------------------------------------- */
128: /*@
129:    PetscBinaryRead - Reads from a binary file.

131:    Not Collective

133:    Input Parameters:
134: +  fd - the file
135: .  n  - the number of items to read 
136: -  type - the type of items to read (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)

138:    Output Parameters:
139: .  p - the buffer



143:    Level: developer

145:    Notes: 
146:    PetscBinaryRead() uses byte swapping to work on all machines; the files
147:    are written to file ALWAYS using big-endian ordering. On small-endian machines the numbers
148:    are converted to the small-endian format when they are read in from the file.
149:    Integers are stored on the file as 32 bits long, regardless of whether
150:    they are stored in the machine as 32 bits or 64 bits, this means the same
151:    binary file may be read on any machine.

153:    Concepts: files^reading binary
154:    Concepts: binary files^reading

156: .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscViewerBinaryGetDescriptor()
157: @*/
158: PetscErrorCode  PetscBinaryRead(int fd,void *p,PetscInt n,PetscDataType type)
159: {
160: #if (PETSC_SIZEOF_INT == 8) || defined(PETSC_USE_64BIT_INDICES) || !defined(PETSC_WORDS_BIGENDIAN)
161:   PetscErrorCode    ierr;
162: #endif
163:   int               wsize,err;
164:   size_t            m = (size_t) n,maxblock = 65536;
165:   char              *pp = (char*)p;
166: #if (PETSC_SIZEOF_INT == 8) || !defined(PETSC_WORDS_BIGENDIAN) || defined(PETSC_USE_64BIT_INDICES)
167:   void              *ptmp = p;
168: #endif

171:   if (!n) return(0);

173:   if (type == PETSC_INT){
174:     m   *= sizeof(PetscInt32);
175: #if (PETSC_SIZEOF_INT == 8) || defined(PETSC_USE_64BIT_INDICES)
176:     /* read them in as 32 bit ints, later stretch into ints */
177:     PetscMalloc(m,&pp);
178:     ptmp = (void*)pp;
179: #endif
180:   }
181:   else if (type == PETSC_SCALAR)  m *= sizeof(PetscScalar);
182:   else if (type == PETSC_DOUBLE)  m *= sizeof(double);
183:   else if (type == PETSC_SHORT)   m *= sizeof(short);
184:   else if (type == PETSC_CHAR)    m *= sizeof(char);
185:   else if (type == PETSC_ENUM)    m *= sizeof(PetscEnum);
186:   else if (type == PETSC_TRUTH)   m *= sizeof(PetscTruth);
187:   else if (type == PETSC_LOGICAL) m  = PetscBTLength(m)*sizeof(char);
188:   else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Unknown type");
189: 
190:   while (m) {
191:     wsize = (m < maxblock) ? m : maxblock;
192:     err = read(fd,pp,wsize);
193:     if (err < 0 && errno == EINTR) continue;
194:     if (!err && wsize > 0) SETERRQ(PETSC_ERR_FILE_READ,"Read past end of file");
195:     if (err < 0) SETERRQ(PETSC_ERR_FILE_READ,"Error reading from file");
196:     m  -= err;
197:     pp += err;
198:   }
199: #if !defined(PETSC_WORDS_BIGENDIAN)
200:   if      (type == PETSC_INT)    {PetscByteSwapInt((PetscInt32*)ptmp,n);}
201:   else if (type == PETSC_ENUM)   {PetscByteSwapInt((PetscInt32*)ptmp,n);}
202:   else if (type == PETSC_TRUTH)  {PetscByteSwapInt((PetscInt32*)ptmp,n);}
203:   else if (type == PETSC_SCALAR) {PetscByteSwapScalar((PetscScalar*)ptmp,n);}
204:   else if (type == PETSC_DOUBLE) {PetscByteSwapDouble((double*)ptmp,n);}
205:   else if (type == PETSC_SHORT)  {PetscByteSwapShort((short*)ptmp,n);}
206: #endif

208: #if (PETSC_SIZEOF_INT == 8) || defined(PETSC_USE_64BIT_INDICES)
209:   if (type == PETSC_INT) {
210:     PetscInt   *p_int = (PetscInt*)p,i;
211:     PetscInt32 *p_short = (PetscInt32 *)ptmp;
212:     for (i=0; i<n; i++) {
213:       p_int[i] = (PetscInt)p_short[i];
214:     }
215:     PetscFree(ptmp);
216:   }
217: #endif
218:   return(0);
219: }
220: /* --------------------------------------------------------- */
223: /*@
224:    PetscBinaryWrite - Writes to a binary file.

226:    Not Collective

228:    Input Parameters:
229: +  fd     - the file
230: .  p      - the buffer
231: .  n      - the number of items to write
232: .  type   - the type of items to read (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)
233: -  istemp - PETSC_FALSE if buffer data should be preserved, PETSC_TRUE otherwise.

235:    Level: advanced

237:    Notes: 
238:    PetscBinaryWrite() uses byte swapping to work on all machines; the files
239:    are written using big-endian ordering to the file. On small-endian machines the numbers
240:    are converted to the big-endian format when they are written to disk.
241:    Integers are stored on the file as 32 bits long, regardless of whether
242:    they are stored in the machine as 32 bits or 64 bits, this means the same
243:    binary file may be read on any machine. It also means that 64 bit integers larger than
244:    roughly 2 billion are TRUNCATED/WRONG when written to the file.

246:    The Buffer p should be read-write buffer, and not static data.
247:    This way, byte-swapping is done in-place, and then the buffer is
248:    written to the file.
249:    
250:    This routine restores the original contents of the buffer, after 
251:    it is written to the file. This is done by byte-swapping in-place 
252:    the second time. If the flag istemp is set to PETSC_TRUE, the second
253:    byte-swapping operation is not done, thus saving some computation,
254:    but the buffer corrupted is corrupted.

256:    Concepts: files^writing binary
257:    Concepts: binary files^writing

259: .seealso: PetscBinaryRead(), PetscBinaryOpen(), PetscBinaryClose(), PetscViewerBinaryGetDescriptor()
260: @*/
261: PetscErrorCode  PetscBinaryWrite(int fd,void *p,PetscInt n,PetscDataType type,PetscTruth istemp)
262: {
263:   char           *pp = (char*)p;
264:   int            err,wsize;
265:   size_t         m = (size_t)n,maxblock=65536;
266: #if !defined(PETSC_WORDS_BIGENDIAN) || (PETSC_SIZEOF_INT == 8) ||  defined(PETSC_USE_64BIT_INDICES)
268:   void           *ptmp = p;
269: #endif

272:   if (n < 0) SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Trying to write a negative amount of data %D",n);
273:   if (!n) return(0);

275:   if (type == PETSC_INT){
276:     m   *= sizeof(PetscInt32);
277: #if (PETSC_SIZEOF_INT == 8) || defined(PETSC_USE_64BIT_INDICES)
278:     PetscInt   *p_int = (PetscInt*)p,i;
279:     PetscInt32 *p_short;
280:     PetscMalloc(m,&pp);
281:     ptmp    = (void*)pp;
282:     p_short = (PetscInt32*)pp;

284:     for (i=0; i<n; i++) {
285:       p_short[i] = (PetscInt32) p_int[i];
286:     }
287:     istemp = PETSC_TRUE;
288: #endif
289:   }
290:   else if (type == PETSC_SCALAR)  m *= sizeof(PetscScalar);
291:   else if (type == PETSC_DOUBLE)  m *= sizeof(double);
292:   else if (type == PETSC_SHORT)   m *= sizeof(short);
293:   else if (type == PETSC_CHAR)    m *= sizeof(char);
294:   else if (type == PETSC_ENUM)    m *= sizeof(PetscEnum);
295:   else if (type == PETSC_TRUTH)   m *= sizeof(PetscTruth);
296:   else if (type == PETSC_LOGICAL) m = PetscBTLength(m)*sizeof(char);
297:   else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Unknown type");

299: #if !defined(PETSC_WORDS_BIGENDIAN)
300:   if      (type == PETSC_INT)    {PetscByteSwapInt((PetscInt32*)ptmp,n);}
301:   else if (type == PETSC_ENUM)   {PetscByteSwapInt((PetscInt32*)ptmp,n);}
302:   else if (type == PETSC_TRUTH)  {PetscByteSwapInt((PetscInt32*)ptmp,n);}
303:   else if (type == PETSC_SCALAR) {PetscByteSwapScalar((PetscScalar*)ptmp,n);}
304:   else if (type == PETSC_DOUBLE) {PetscByteSwapDouble((double*)ptmp,n);}
305:   else if (type == PETSC_SHORT)  {PetscByteSwapShort((short*)ptmp,n);}
306: #endif

308:   while (m) {
309:     wsize = (m < maxblock) ? m : maxblock;
310:     err = write(fd,pp,wsize);
311:     if (err < 0 && errno == EINTR) continue;
312:     if (err != wsize) SETERRQ(PETSC_ERR_FILE_WRITE,"Error writing to file.");
313:     m -= wsize;
314:     pp += wsize;
315:   }

317: #if !defined(PETSC_WORDS_BIGENDIAN) && !(PETSC_SIZEOF_INT == 8) && !defined(PETSC_USE_64BIT_INDICES)
318:   if (!istemp) {
319:     if      (type == PETSC_SCALAR) {PetscByteSwapScalar((PetscScalar*)ptmp,n);}
320:     else if (type == PETSC_SHORT)  {PetscByteSwapShort((short*)ptmp,n);}
321:     else if (type == PETSC_INT)    {PetscByteSwapInt((PetscInt32*)ptmp,n);}
322:     else if (type == PETSC_ENUM)   {PetscByteSwapInt((PetscInt32*)ptmp,n);}
323:     else if (type == PETSC_TRUTH)  {PetscByteSwapInt((PetscInt32*)ptmp,n);}
324:   }
325: #endif

327: #if (PETSC_SIZEOF_INT == 8) || defined(PETSC_USE_64BIT_INDICES)
328:   if (type == PETSC_INT){
329:     PetscFree(ptmp);
330:   }
331: #endif
332:   return(0);
333: }

337: /*@C
338:    PetscBinaryOpen - Opens a PETSc binary file.

340:    Not Collective

342:    Input Parameters:
343: +  name - filename
344: -  type - type of binary file, one of FILE_MODE_READ, FILE_MODE_APPEND, FILE_MODE_WRITE

346:    Output Parameter:
347: .  fd - the file

349:    Level: advanced

351:   Concepts: files^opening binary
352:   Concepts: binary files^opening

354:    Notes: Files access with PetscBinaryRead() and PetscBinaryWrite() are ALWAYS written in
355:    big-endian format. This means the file can be accessed using PetscBinaryOpen() and
356:    PetscBinaryRead() and PetscBinaryWrite() on any machine.

358: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscFileMode, PetscViewerFileSetMode(), PetscViewerBinaryGetDescriptor()

360: @*/
361: PetscErrorCode  PetscBinaryOpen(const char name[],PetscFileMode mode,int *fd)
362: {
364: #if defined(PETSC_HAVE_O_BINARY) 
365:   if (mode == FILE_MODE_WRITE) {
366:     if ((*fd = open(name,O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,0666)) == -1) {
367:       SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot create file for writing: %s",name);
368:     }
369:   } else if (mode == FILE_MODE_READ) {
370:     if ((*fd = open(name,O_RDONLY|O_BINARY,0)) == -1) {
371:       SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot open file for reading: %s",name);
372:     }
373:   } else if (mode == FILE_MODE_APPEND) {
374:     if ((*fd = open(name,O_WRONLY|O_BINARY,0)) == -1) {
375:       SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot open file for writing: %s",name);
376:     }
377: #else
378:   if (mode == FILE_MODE_WRITE) {
379:     if ((*fd = creat(name,0666)) == -1) {
380:       SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot create file for writing: %s",name);
381:     }
382:   } else if (mode == FILE_MODE_READ) {
383:     if ((*fd = open(name,O_RDONLY,0)) == -1) {
384:       SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot open file for reading: %s",name);
385:     }
386:   }
387:   else if (mode == FILE_MODE_APPEND) {
388:     if ((*fd = open(name,O_WRONLY,0)) == -1) {
389:       SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot open file for writing: %s",name);
390:     }
391: #endif
392:   } else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Unknown file mode");
393:   return(0);
394: }

398: /*@
399:    PetscBinaryClose - Closes a PETSc binary file.

401:    Not Collective

403:    Output Parameter:
404: .  fd - the file

406:    Level: advanced

408: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen()
409: @*/
410: PetscErrorCode  PetscBinaryClose(int fd)
411: {
413:   close(fd);
414:   return(0);
415: }


420: /*@
421:    PetscBinarySeek - Moves the file pointer on a PETSc binary file.

423:    Not Collective

425:    Input Parameters:
426: +  fd - the file
427: .  off - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE,
428:             etc. in your calculation rather than sizeof() to compute byte lengths.
429: -  whence - if PETSC_BINARY_SEEK_SET then off is an absolute location in the file
430:             if PETSC_BINARY_SEEK_CUR then off is an offset from the current location
431:             if PETSC_BINARY_SEEK_END then off is an offset from the end of file

433:    Output Parameter:
434: .   offset - new offset in file

436:    Level: developer

438:    Notes: 
439:    Integers are stored on the file as 32 long, regardless of whether
440:    they are stored in the machine as 32 or 64, this means the same
441:    binary file may be read on any machine. Hence you CANNOT use sizeof()
442:    to determine the offset or location.

444:    Concepts: files^binary seeking
445:    Concepts: binary files^seeking

447: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen()
448: @*/
449: PetscErrorCode  PetscBinarySeek(int fd,off_t off,PetscBinarySeekType whence,off_t *offset)
450: {
451:   int iwhence = 0;

454:   if (whence == PETSC_BINARY_SEEK_SET) {
455:     iwhence = SEEK_SET;
456:   } else if (whence == PETSC_BINARY_SEEK_CUR) {
457:     iwhence = SEEK_CUR;
458:   } else if (whence == PETSC_BINARY_SEEK_END) {
459:     iwhence = SEEK_END;
460:   } else {
461:     SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Unknown seek location");
462:   }
463: #if defined(PETSC_HAVE_LSEEK)
464:   *offset = lseek(fd,off,iwhence);
465: #elif defined(PETSC_HAVE__LSEEK)
466:   *offset = _lseek(fd,(long)off,iwhence);
467: #else
468:   SETERRQ(PETSC_ERR_SUP_SYS,"System does not have a way of seeking on a file");
469: #endif
470:   return(0);
471: }

475: /*@C
476:    PetscSynchronizedBinaryRead - Reads from a binary file.

478:    Collective on MPI_Comm

480:    Input Parameters:
481: +  comm - the MPI communicator 
482: .  fd - the file
483: .  n  - the number of items to read 
484: -  type - the type of items to read (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)

486:    Output Parameters:
487: .  p - the buffer

489:    Options Database Key:
490: .   -binary_longints - indicates the file was generated on a Cray vector 
491:          machine (not the T3E/D) and the ints are stored as 64 bit 
492:          quantities, otherwise they are stored as 32 bit

494:    Level: developer

496:    Notes: 
497:    Does a PetscBinaryRead() followed by an MPI_Bcast()

499:    PetscSynchronizedBinaryRead() uses byte swapping to work on all machines.
500:    Integers are stored on the file as 32 long, regardless of whether
501:    they are stored in the machine as 32 or 64, this means the same
502:    binary file may be read on any machine.

504:    Concepts: files^synchronized reading of binary files
505:    Concepts: binary files^reading, synchronized

507: .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead()
508: @*/
509: PetscErrorCode  PetscSynchronizedBinaryRead(MPI_Comm comm,int fd,void *p,PetscInt n,PetscDataType type)
510: {
512:   PetscMPIInt    rank;
513:   MPI_Datatype   mtype;

516:   MPI_Comm_rank(comm,&rank);
517:   if (!rank) {
518:     PetscBinaryRead(fd,p,n,type);
519:   }
520:   PetscDataTypeToMPIDataType(type,&mtype);
521:   MPI_Bcast(p,n,mtype,0,comm);
522:   return(0);
523: }

527: /*@C
528:    PetscSynchronizedBinaryWrite - writes to a binary file.

530:    Collective on MPI_Comm

532:    Input Parameters:
533: +  comm - the MPI communicator 
534: .  fd - the file
535: .  n  - the number of items to write
536: .  p - the buffer
537: .  istemp - the buffer may be changed
538: -  type - the type of items to write (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)

540:    Level: developer

542:    Notes: 
543:    Process 0 does a PetscBinaryWrite()

545:    PetscSynchronizedBinaryWrite() uses byte swapping to work on all machines.
546:    Integers are stored on the file as 32 long, regardless of whether
547:    they are stored in the machine as 32 or 64, this means the same
548:    binary file may be read on any machine.

550:    Concepts: files^synchronized writing of binary files
551:    Concepts: binary files^reading, synchronized

553: .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead()
554: @*/
555: PetscErrorCode  PetscSynchronizedBinaryWrite(MPI_Comm comm,int fd,void *p,PetscInt n,PetscDataType type,PetscTruth istemp)
556: {
558:   PetscMPIInt    rank;

561:   MPI_Comm_rank(comm,&rank);
562:   if (!rank) {
563:     PetscBinaryWrite(fd,p,n,type,istemp);
564:   }
565:   return(0);
566: }

570: /*@C
571:    PetscSynchronizedBinarySeek - Moves the file pointer on a PETSc binary file.


574:    Input Parameters:
575: +  fd - the file
576: .  whence - if PETSC_BINARY_SEEK_SET then size is an absolute location in the file
577:             if PETSC_BINARY_SEEK_CUR then size is offset from current location
578:             if PETSC_BINARY_SEEK_END then size is offset from end of file
579: -  off    - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE,
580:             etc. in your calculation rather than sizeof() to compute byte lengths.

582:    Output Parameter:
583: .   offset - new offset in file

585:    Level: developer

587:    Notes: 
588:    Integers are stored on the file as 32 long, regardless of whether
589:    they are stored in the machine as 32 or 64, this means the same
590:    binary file may be read on any machine. Hence you CANNOT use sizeof()
591:    to determine the offset or location.

593:    Concepts: binary files^seeking
594:    Concepts: files^seeking in binary 

596: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen()
597: @*/
598: PetscErrorCode  PetscSynchronizedBinarySeek(MPI_Comm comm,int fd,off_t off,PetscBinarySeekType whence,off_t *offset)
599: {
601:   PetscMPIInt    rank;

604:   MPI_Comm_rank(comm,&rank);
605:   if (!rank) {
606:     PetscBinarySeek(fd,off,whence,offset);
607:   }
608:   return(0);
609: }