/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ /* * Shell file I/O routines */ #include "sh.h"#include "ksh_stat.h"#include "ksh_limval.h" /* flags to shf_emptybuf() */#define EB_READSW 0x01 /* about to switch to reading */#define EB_GROW 0x02 /* grow buffer if necessary (STRING+DYNAMIC) */ /* * Replacement stdio routines. Stdio is too flakey on too many machines * to be useful when you have multiple processes using the same underlying * file descriptors. */ static int shf_fillbuf ARGS((struct shf *shf));static int shf_emptybuf ARGS((struct shf *shf, int flags)); /* Open a file. First three args are for open(), last arg is flags for * this package. Returns NULL if file could not be opened, or if a dup * fails. */struct shf *shf_open(name, oflags, mode, sflags) const char *name; int oflags; int mode; int sflags;{ struct shf *shf; int bsize = sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE; int fd; /* Done before open so if alloca fails, fd won't be lost. */ shf = (struct shf *) alloc(sizeof(struct shf) + bsize, ATEMP); shf->areap = ATEMP; shf->buf = (unsigned char *) &shf[1]; shf->bsize = bsize; shf->flags = SHF_ALLOCS; /* Rest filled in by reopen. */ fd = open(name, oflags, mode); if (fd < 0) { afree(shf, shf->areap); return NULL; } if ((sflags & SHF_MAPHI) && fd < FDBASE) { int nfd; nfd = ksh_dupbase(fd, FDBASE); close(fd); if (nfd < 0) { afree(shf, shf->areap); return NULL; } fd = nfd; } sflags &= ~SHF_ACCMODE; sflags |= (oflags & O_ACCMODE) == O_RDONLY ? SHF_RD : ((oflags & O_ACCMODE) == O_WRONLY ? SHF_WR : SHF_RDWR); return shf_reopen(fd, sflags, shf);} /* Set up the shf structure for a file descriptor. Doesn't fail. */struct shf *shf_fdopen(fd, sflags, shf) int fd; int sflags; struct shf *shf;{ int bsize = sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE; /* use fcntl() to figure out correct read/write flags */ if (sflags & SHF_GETFL) { int flags = fcntl(fd, F_GETFL, 0); if (flags < 0) /* will get an error on first read/write */ sflags |= SHF_RDWR; else switch (flags & O_ACCMODE) { case O_RDONLY: sflags |= SHF_RD; break; case O_WRONLY: sflags |= SHF_WR; break; case O_RDWR: sflags |= SHF_RDWR; break; } } if (!(sflags & (SHF_RD | SHF_WR))) internal_errorf(1, "shf_fdopen: missing read/write"); if (shf) { if (bsize) { shf->buf = (unsigned char *) alloc(bsize, ATEMP); sflags |= SHF_ALLOCB; } else shf->buf = (unsigned char *) 0; } else { shf = (struct shf *) alloc(sizeof(struct shf) + bsize, ATEMP); shf->buf = (unsigned char *) &shf[1]; sflags |= SHF_ALLOCS; } shf->areap = ATEMP; shf->fd = fd; shf->rp = shf->wp = shf->buf; shf->rnleft = 0; shf->rbsize = bsize; shf->wnleft = 0; /* force call to shf_emptybuf() */ shf->wbsize = sflags & SHF_UNBUF ? 0 : bsize; shf->flags = sflags; shf->errno_ = 0; shf->bsize = bsize; if (sflags & SHF_CLEXEC) fd_clexec(fd); return shf;} /* Set up an existing shf (and buffer) to use the given fd */struct shf *shf_reopen(fd, sflags, shf) int fd; int sflags; struct shf *shf;{ int bsize = sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE; /* use fcntl() to figure out correct read/write flags */ if (sflags & SHF_GETFL) { int flags = fcntl(fd, F_GETFL, 0); if (flags < 0) /* will get an error on first read/write */ sflags |= SHF_RDWR; else switch (flags & O_ACCMODE) { case O_RDONLY: sflags |= SHF_RD; break; case O_WRONLY: sflags |= SHF_WR; break; case O_RDWR: sflags |= SHF_RDWR; break; } } if (!(sflags & (SHF_RD | SHF_WR))) internal_errorf(1, "shf_reopen: missing read/write"); if (!shf || !shf->buf || shf->bsize < bsize) internal_errorf(1, "shf_reopen: bad shf/buf/bsize"); /* assumes shf->buf and shf->bsize already set up */ shf->fd = fd; shf->rp = shf->wp = shf->buf; shf->rnleft = 0; shf->rbsize = bsize; shf->wnleft = 0; /* force call to shf_emptybuf() */ shf->wbsize = sflags & SHF_UNBUF ? 0 : bsize; shf->flags = (shf->flags & (SHF_ALLOCS | SHF_ALLOCB)) | sflags; shf->errno_ = 0; if (sflags & SHF_CLEXEC) fd_clexec(fd); return shf;} /* Open a string for reading or writing. If reading, bsize is the number * of bytes that can be read. If writing, bsize is the maximum number of * bytes that can be written. If shf is not null, it is filled in and * returned, if it is null, shf is allocated. If writing and buf is null * and SHF_DYNAMIC is set, the buffer is allocated (if bsize > 0, it is * used for the initial size). Doesn't fail. * When writing, a byte is reserved for a trailing null - see shf_sclose(). */struct shf *shf_sopen(buf, bsize, sflags, shf) char *buf; int bsize; int sflags; struct shf *shf;{ /* can't have a read+write string */ if (!(sflags & (SHF_RD | SHF_WR)) || (sflags & (SHF_RD | SHF_WR)) == (SHF_RD | SHF_WR)) internal_errorf(1, "shf_sopen: flags 0x%x", sflags); if (!shf) { shf = (struct shf *) alloc(sizeof(struct shf), ATEMP); sflags |= SHF_ALLOCS; } shf->areap = ATEMP; if (!buf && (sflags & SHF_WR) && (sflags & SHF_DYNAMIC)) { if (bsize <= 0) bsize = 64; sflags |= SHF_ALLOCB; buf = alloc(bsize, shf->areap); } shf->fd = -1; shf->buf = shf->rp = shf->wp = (unsigned char *) buf; shf->rnleft = bsize; shf->rbsize = bsize; shf->wnleft = bsize - 1; /* space for a '\0' */ shf->wbsize = bsize; shf->flags = sflags | SHF_STRING; shf->errno_ = 0; shf->bsize = bsize; return shf;} /* Flush and close file descriptor, free the shf structure */intshf_close(shf) struct shf *shf;{ int ret = 0; if (shf->fd >= 0) { ret = shf_flush(shf); if (close(shf->fd) < 0) ret = EOF; } if (shf->flags & SHF_ALLOCS) afree(shf, shf->areap); else if (shf->flags & SHF_ALLOCB) afree(shf->buf, shf->areap); return ret;} /* Flush and close file descriptor, don't free file structure */intshf_fdclose(shf) struct shf *shf;{ int ret = 0; if (shf->fd >= 0) { ret = shf_flush(shf); if (close(shf->fd) < 0) ret = EOF; shf->rnleft = 0; shf->rp = shf->buf; shf->wnleft = 0; shf->fd = -1; } return ret;} /* Close a string - if it was opened for writing, it is null terminated; * returns a pointer to the string and frees shf if it was allocated * (does not free string if it was allocated). */char *shf_sclose(shf) struct shf *shf;{ unsigned char *s = shf->buf; /* null terminate */ if (shf->flags & SHF_WR) { shf->wnleft++; shf_putc('\0', shf); } if (shf->flags & SHF_ALLOCS) afree(shf, shf->areap); return (char *) s;} /* Flush and free file structure, don't close file descriptor */intshf_finish(shf) struct shf *shf;{ int ret = 0; if (shf->fd >= 0) ret = shf_flush(shf); if (shf->flags & SHF_ALLOCS) afree(shf, shf->areap); else if (shf->flags & SHF_ALLOCB) afree(shf->buf, shf->areap); return ret;} /* Un-read what has been read but not examined, or write what has been * buffered. Returns 0 for success, EOF for (write) error. */intshf_flush(shf) struct shf *shf;{ if (shf->flags & SHF_STRING) return (shf->flags & SHF_WR) ? EOF : 0; if (shf->fd < 0) internal_errorf(1, "shf_flush: no fd"); if (shf->flags & SHF_ERROR) { errno = shf->errno_; return EOF; } if (shf->flags & SHF_READING) { shf->flags &= ~(SHF_EOF | SHF_READING); if (shf->rnleft > 0) { lseek(shf->fd, (off_t) -shf->rnleft, 1); shf->rnleft = 0; shf->rp = shf->buf; } return 0; } else if (shf->flags & SHF_WRITING) return shf_emptybuf(shf, 0); return 0;} /* Write out any buffered data. If currently reading, flushes the read * buffer. Returns 0 for success, EOF for (write) error. */static intshf_emptybuf(shf, flags) struct shf *shf; int flags;{ int ret = 0; if (!(shf->flags & SHF_STRING) && shf->fd < 0) internal_errorf(1, "shf_emptybuf: no fd"); if (shf->flags & SHF_ERROR) { errno = shf->errno_; return EOF; } if (shf->flags & SHF_READING) { if (flags & EB_READSW) /* doesn't happen */ return 0; ret = shf_flush(shf); shf->flags &= ~SHF_READING; } if (shf->flags & SHF_STRING) { unsigned char *nbuf; /* Note that we assume SHF_ALLOCS is not set if SHF_ALLOCB * is set... (changing the shf pointer could cause problems) */ if (!(flags & EB_GROW) || !(shf->flags & SHF_DYNAMIC) || !(shf->flags & SHF_ALLOCB)) return EOF; /* allocate more space for buffer */ nbuf = (unsigned char *) aresize(shf->buf, shf->wbsize * 2, shf->areap); shf->rp = nbuf + (shf->rp - shf->buf); shf->wp = nbuf + (shf->wp - shf->buf); shf->rbsize += shf->wbsize; shf->wbsize += shf->wbsize; shf->wnleft += shf->wbsize; shf->wbsize *= 2; shf->buf = nbuf; } else { if (shf->flags & SHF_WRITING) { int ntowrite = shf->wp - shf->buf; unsigned char *buf = shf->buf; int n; while (ntowrite > 0) { n = write(shf->fd, buf, ntowrite); if (n < 0) { if (errno == EINTR && !(shf->flags & SHF_INTERRUPT)) continue; shf->flags |= SHF_ERROR; shf->errno_ = errno; shf->wnleft = 0; if (buf != shf->buf) { /* allow a second flush * to work */ memmove(shf->buf, buf, ntowrite); shf->wp = shf->buf + ntowrite; } return EOF; } buf += n; ntowrite -= n; } if (flags & EB_READSW) { shf->wp = shf->buf; shf->wnleft = 0; shf->flags &= ~SHF_WRITING; return 0; } } shf->wp = shf->buf; shf->wnleft = shf->wbsize; } shf->flags |= SHF_WRITING; return ret;} /* Fill up a read buffer. Returns EOF for a read error, 0 otherwise. */static intshf_fillbuf(shf) struct shf *shf;{ if (shf->flags & SHF_STRING) return 0; if (shf->fd < 0) internal_errorf(1, "shf_fillbuf: no fd"); if (shf->flags & (SHF_EOF | SHF_ERROR)) { if (shf->flags & SHF_ERROR) errno = shf->errno_; return EOF; } if ((shf->flags & SHF_WRITING) && shf_emptybuf(shf, EB_READSW) == EOF) return EOF; shf->flags |= SHF_READING; shf->rp = shf->buf; while (1) { shf->rnleft = blocking_read(shf->fd, (char *) shf->buf, shf->rbsize); if (shf->rnleft < 0 && errno == EINTR && !(shf->flags & SHF_INTERRUPT)) continue; break; } if (shf->rnleft <= 0) { if (shf->rnleft < 0) { shf->flags |= SHF_ERROR; shf->errno_ = errno; shf->rnleft = 0; shf->rp = shf->buf; return EOF; } shf->flags |= SHF_EOF; } return 0;} /* Seek to a new position in the file. If writing, flushes the buffer * first. If reading, optimizes small relative seeks that stay inside the * buffer. Returns 0 for success, EOF otherwise. */intshf_seek(shf, where, from) struct shf *shf; off_t where; int from;{ if (shf->fd < 0) { errno = EINVAL; return EOF; } if (shf->flags & SHF_ERROR) { errno = shf->errno_; return EOF; } if ((shf->flags & SHF_WRITING) && shf_emptybuf(shf, EB_READSW) == EOF) return EOF; if (shf->flags & SHF_READING) { if (from == SEEK_CUR && (where < 0 ? -where >= shf->rbsize - shf->rnleft : where < shf->rnleft)) { shf->rnleft -= where; shf->rp += where; return 0; } shf->rnleft = 0; shf->rp = shf->buf; } shf->flags &= ~(SHF_EOF | SHF_READING | SHF_WRITING); if (lseek(shf->fd, where, from) < 0) { shf->errno_ = errno; shf->flags |= SHF_ERROR; return EOF; } Lines 1–500 of 1303. Load more
/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ /* * Shell file I/O routines */ #include "sh.h" #include "ksh_stat.h" #include "ksh_limval.h" /* flags to shf_emptybuf() */ #define EB_READSW 0x01 /* about to switch to reading */ #define EB_GROW 0x02 /* grow buffer if necessary (STRING+DYNAMIC) */ /* * Replacement stdio routines. Stdio is too flakey on too many machines * to be useful when you have multiple processes using the same underlying * file descriptors. */ static int shf_fillbuf ARGS((struct shf *shf)); static int shf_emptybuf ARGS((struct shf *shf, int flags)); /* Open a file. First three args are for open(), last arg is flags for * this package. Returns NULL if file could not be opened, or if a dup * fails. */ struct shf * shf_open(name, oflags, mode, sflags) const char *name; int oflags; int mode; int sflags; { struct shf *shf; int bsize = sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE; int fd; /* Done before open so if alloca fails, fd won't be lost. */ shf = (struct shf *) alloc(sizeof(struct shf) + bsize, ATEMP); shf->areap = ATEMP; shf->buf = (unsigned char *) &shf[1]; shf->bsize = bsize; shf->flags = SHF_ALLOCS; /* Rest filled in by reopen. */ fd = open(name, oflags, mode); if (fd < 0) { afree(shf, shf->areap); return NULL; } if ((sflags & SHF_MAPHI) && fd < FDBASE) { int nfd; nfd = ksh_dupbase(fd, FDBASE); close(fd); if (nfd < 0) { afree(shf, shf->areap); return NULL; } fd = nfd; } sflags &= ~SHF_ACCMODE; sflags |= (oflags & O_ACCMODE) == O_RDONLY ? SHF_RD : ((oflags & O_ACCMODE) == O_WRONLY ? SHF_WR : SHF_RDWR); return shf_reopen(fd, sflags, shf); } /* Set up the shf structure for a file descriptor. Doesn't fail. */ struct shf * shf_fdopen(fd, sflags, shf) int fd; int sflags; struct shf *shf; { int bsize = sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE; /* use fcntl() to figure out correct read/write flags */ if (sflags & SHF_GETFL) { int flags = fcntl(fd, F_GETFL, 0); if (flags < 0) /* will get an error on first read/write */ sflags |= SHF_RDWR; else switch (flags & O_ACCMODE) { case O_RDONLY: sflags |= SHF_RD; break; case O_WRONLY: sflags |= SHF_WR; break; case O_RDWR: sflags |= SHF_RDWR; break; } } if (!(sflags & (SHF_RD | SHF_WR))) internal_errorf(1, "shf_fdopen: missing read/write"); if (shf) { if (bsize) { shf->buf = (unsigned char *) alloc(bsize, ATEMP); sflags |= SHF_ALLOCB; } else shf->buf = (unsigned char *) 0; } else { shf = (struct shf *) alloc(sizeof(struct shf) + bsize, ATEMP); shf->buf = (unsigned char *) &shf[1]; sflags |= SHF_ALLOCS; } shf->areap = ATEMP; shf->fd = fd; shf->rp = shf->wp = shf->buf; shf->rnleft = 0; shf->rbsize = bsize; shf->wnleft = 0; /* force call to shf_emptybuf() */ shf->wbsize = sflags & SHF_UNBUF ? 0 : bsize; shf->flags = sflags; shf->errno_ = 0; shf->bsize = bsize; if (sflags & SHF_CLEXEC) fd_clexec(fd); return shf; } /* Set up an existing shf (and buffer) to use the given fd */ struct shf * shf_reopen(fd, sflags, shf) int fd; int sflags; struct shf *shf; { int bsize = sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE; /* use fcntl() to figure out correct read/write flags */ if (sflags & SHF_GETFL) { int flags = fcntl(fd, F_GETFL, 0); if (flags < 0) /* will get an error on first read/write */ sflags |= SHF_RDWR; else switch (flags & O_ACCMODE) { case O_RDONLY: sflags |= SHF_RD; break; case O_WRONLY: sflags |= SHF_WR; break; case O_RDWR: sflags |= SHF_RDWR; break; } } if (!(sflags & (SHF_RD | SHF_WR))) internal_errorf(1, "shf_reopen: missing read/write"); if (!shf || !shf->buf || shf->bsize < bsize) internal_errorf(1, "shf_reopen: bad shf/buf/bsize"); /* assumes shf->buf and shf->bsize already set up */ shf->fd = fd; shf->rp = shf->wp = shf->buf; shf->rnleft = 0; shf->rbsize = bsize; shf->wnleft = 0; /* force call to shf_emptybuf() */ shf->wbsize = sflags & SHF_UNBUF ? 0 : bsize; shf->flags = (shf->flags & (SHF_ALLOCS | SHF_ALLOCB)) | sflags; shf->errno_ = 0; if (sflags & SHF_CLEXEC) fd_clexec(fd); return shf; } /* Open a string for reading or writing. If reading, bsize is the number * of bytes that can be read. If writing, bsize is the maximum number of * bytes that can be written. If shf is not null, it is filled in and * returned, if it is null, shf is allocated. If writing and buf is null * and SHF_DYNAMIC is set, the buffer is allocated (if bsize > 0, it is * used for the initial size). Doesn't fail. * When writing, a byte is reserved for a trailing null - see shf_sclose(). */ struct shf * shf_sopen(buf, bsize, sflags, shf) char *buf; int bsize; int sflags; struct shf *shf; { /* can't have a read+write string */ if (!(sflags & (SHF_RD | SHF_WR)) || (sflags & (SHF_RD | SHF_WR)) == (SHF_RD | SHF_WR)) internal_errorf(1, "shf_sopen: flags 0x%x", sflags); if (!shf) { shf = (struct shf *) alloc(sizeof(struct shf), ATEMP); sflags |= SHF_ALLOCS; } shf->areap = ATEMP; if (!buf && (sflags & SHF_WR) && (sflags & SHF_DYNAMIC)) { if (bsize <= 0) bsize = 64; sflags |= SHF_ALLOCB; buf = alloc(bsize, shf->areap); } shf->fd = -1; shf->buf = shf->rp = shf->wp = (unsigned char *) buf; shf->rnleft = bsize; shf->rbsize = bsize; shf->wnleft = bsize - 1; /* space for a '\0' */ shf->wbsize = bsize; shf->flags = sflags | SHF_STRING; shf->errno_ = 0; shf->bsize = bsize; return shf; } /* Flush and close file descriptor, free the shf structure */ int shf_close(shf) struct shf *shf; { int ret = 0; if (shf->fd >= 0) { ret = shf_flush(shf); if (close(shf->fd) < 0) ret = EOF; } if (shf->flags & SHF_ALLOCS) afree(shf, shf->areap); else if (shf->flags & SHF_ALLOCB) afree(shf->buf, shf->areap); return ret; } /* Flush and close file descriptor, don't free file structure */ int shf_fdclose(shf) struct shf *shf; { int ret = 0; if (shf->fd >= 0) { ret = shf_flush(shf); if (close(shf->fd) < 0) ret = EOF; shf->rnleft = 0; shf->rp = shf->buf; shf->wnleft = 0; shf->fd = -1; } return ret; } /* Close a string - if it was opened for writing, it is null terminated; * returns a pointer to the string and frees shf if it was allocated * (does not free string if it was allocated). */ char * shf_sclose(shf) struct shf *shf; { unsigned char *s = shf->buf; /* null terminate */ if (shf->flags & SHF_WR) { shf->wnleft++; shf_putc('\0', shf); } if (shf->flags & SHF_ALLOCS) afree(shf, shf->areap); return (char *) s; } /* Flush and free file structure, don't close file descriptor */ int shf_finish(shf) struct shf *shf; { int ret = 0; if (shf->fd >= 0) ret = shf_flush(shf); if (shf->flags & SHF_ALLOCS) afree(shf, shf->areap); else if (shf->flags & SHF_ALLOCB) afree(shf->buf, shf->areap); return ret; } /* Un-read what has been read but not examined, or write what has been * buffered. Returns 0 for success, EOF for (write) error. */ int shf_flush(shf) struct shf *shf; { if (shf->flags & SHF_STRING) return (shf->flags & SHF_WR) ? EOF : 0; if (shf->fd < 0) internal_errorf(1, "shf_flush: no fd"); if (shf->flags & SHF_ERROR) { errno = shf->errno_; return EOF; } if (shf->flags & SHF_READING) { shf->flags &= ~(SHF_EOF | SHF_READING); if (shf->rnleft > 0) { lseek(shf->fd, (off_t) -shf->rnleft, 1); shf->rnleft = 0; shf->rp = shf->buf; } return 0; } else if (shf->flags & SHF_WRITING) return shf_emptybuf(shf, 0); return 0; } /* Write out any buffered data. If currently reading, flushes the read * buffer. Returns 0 for success, EOF for (write) error. */ static int shf_emptybuf(shf, flags) struct shf *shf; int flags; { int ret = 0; if (!(shf->flags & SHF_STRING) && shf->fd < 0) internal_errorf(1, "shf_emptybuf: no fd"); if (shf->flags & SHF_ERROR) { errno = shf->errno_; return EOF; } if (shf->flags & SHF_READING) { if (flags & EB_READSW) /* doesn't happen */ return 0; ret = shf_flush(shf); shf->flags &= ~SHF_READING; } if (shf->flags & SHF_STRING) { unsigned char *nbuf; /* Note that we assume SHF_ALLOCS is not set if SHF_ALLOCB * is set... (changing the shf pointer could cause problems) */ if (!(flags & EB_GROW) || !(shf->flags & SHF_DYNAMIC) || !(shf->flags & SHF_ALLOCB)) return EOF; /* allocate more space for buffer */ nbuf = (unsigned char *) aresize(shf->buf, shf->wbsize * 2, shf->areap); shf->rp = nbuf + (shf->rp - shf->buf); shf->wp = nbuf + (shf->wp - shf->buf); shf->rbsize += shf->wbsize; shf->wbsize += shf->wbsize; shf->wnleft += shf->wbsize; shf->wbsize *= 2; shf->buf = nbuf; } else { if (shf->flags & SHF_WRITING) { int ntowrite = shf->wp - shf->buf; unsigned char *buf = shf->buf; int n; while (ntowrite > 0) { n = write(shf->fd, buf, ntowrite); if (n < 0) { if (errno == EINTR && !(shf->flags & SHF_INTERRUPT)) continue; shf->flags |= SHF_ERROR; shf->errno_ = errno; shf->wnleft = 0; if (buf != shf->buf) { /* allow a second flush * to work */ memmove(shf->buf, buf, ntowrite); shf->wp = shf->buf + ntowrite; } return EOF; } buf += n; ntowrite -= n; } if (flags & EB_READSW) { shf->wp = shf->buf; shf->wnleft = 0; shf->flags &= ~SHF_WRITING; return 0; } } shf->wp = shf->buf; shf->wnleft = shf->wbsize; } shf->flags |= SHF_WRITING; return ret; } /* Fill up a read buffer. Returns EOF for a read error, 0 otherwise. */ static int shf_fillbuf(shf) struct shf *shf; { if (shf->flags & SHF_STRING) return 0; if (shf->fd < 0) internal_errorf(1, "shf_fillbuf: no fd"); if (shf->flags & (SHF_EOF | SHF_ERROR)) { if (shf->flags & SHF_ERROR) errno = shf->errno_; return EOF; } if ((shf->flags & SHF_WRITING) && shf_emptybuf(shf, EB_READSW) == EOF) return EOF; shf->flags |= SHF_READING; shf->rp = shf->buf; while (1) { shf->rnleft = blocking_read(shf->fd, (char *) shf->buf, shf->rbsize); if (shf->rnleft < 0 && errno == EINTR && !(shf->flags & SHF_INTERRUPT)) continue; break; } if (shf->rnleft <= 0) { if (shf->rnleft < 0) { shf->flags |= SHF_ERROR; shf->errno_ = errno; shf->rnleft = 0; shf->rp = shf->buf; return EOF; } shf->flags |= SHF_EOF; } return 0; } /* Seek to a new position in the file. If writing, flushes the buffer * first. If reading, optimizes small relative seeks that stay inside the * buffer. Returns 0 for success, EOF otherwise. */ int shf_seek(shf, where, from) struct shf *shf; off_t where; int from; { if (shf->fd < 0) { errno = EINVAL; return EOF; } if (shf->flags & SHF_ERROR) { errno = shf->errno_; return EOF; } if ((shf->flags & SHF_WRITING) && shf_emptybuf(shf, EB_READSW) == EOF) return EOF; if (shf->flags & SHF_READING) { if (from == SEEK_CUR && (where < 0 ? -where >= shf->rbsize - shf->rnleft : where < shf->rnleft)) { shf->rnleft -= where; shf->rp += where; return 0; } shf->rnleft = 0; shf->rp = shf->buf; } shf->flags &= ~(SHF_EOF | SHF_READING | SHF_WRITING); if (lseek(shf->fd, where, from) < 0) { shf->errno_ = errno; shf->flags |= SHF_ERROR; return EOF; }