/* I/O and memory routines safe for use by multiple simultaneous processes. * C library's fopen(), etc. are kept around because stdin/out/err are still * (relatively) safe to use. Our file routines return pointers to mFILE's. * These pointers cannot be shared between processes, but do not rely on any * shared data (i.e. descriptor tables, buffers). */ #include "httpd.h" #include #include #include void *malloc(size_t size) { return AllocVec(size, MEMF_PUBLIC); } void *calloc(size_t elsize, size_t els) { return AllocVec(elsize * els, MEMF_PUBLIC | MEMF_CLEAR); } void free(void *ptr) { FreeVec(ptr); } void *realloc(void *old, size_t newsize) { void *new = malloc(newsize); if (old) { if (new) CopyMem(old, new, newsize); free(old); } return new; } /********************/ /* 'modes' can only be "r[+]", "w[+]", or "a" */ mFILE *Fopen(const char *name, const char *modes) { mFILE *f; if (!(f = malloc(sizeof(mFILE)))) return NULL; f->bufsize = 1024; if (!(f->buf = malloc(f->bufsize))) { free(f); return NULL; } if (*modes == 'r') { f->flags = MF_READ | MF_SEEK; f->fh = Open(name, MODE_OLDFILE); } else if (*modes == 'w') { f->flags = MF_WRITE | MF_SEEK; f->fh = Open(name, MODE_NEWFILE); } else if (*modes == 'a') { f->flags = MF_WRITE; if (f->fh = Open(name, MODE_OLDFILE)) { Seek(f->fh, 0, OFFSET_END); } else { f->fh = Open(name, MODE_NEWFILE); if (f->fh) { Close(f->fh); f->fh = Open(name, MODE_OLDFILE); } } } else { free(f->buf); free(f); return NULL; } if (!f->fh) { free(f->buf); free(f); return NULL; } if (modes[1] == '+' && *modes != 'a') f->flags |= (MF_READ | MF_WRITE); f->rleft = f->wleft = -1; return f; } /* Duplicate a file handle. Does an implicit Fflush() on the file. NOTE: * this doesn't actually re-open the file - it just allocates a new mFILE * and buffer and copies the AmigaDOS file handle. Hopefully, the system * knows how to handle simultaneous writes to the same file handle... */ mFILE *Fdup(mFILE *f) { mFILE *new; if (!(new = malloc(sizeof(mFILE)))) return NULL; new->bufsize = f->bufsize; if (!(new->buf = malloc(new->bufsize))) { free(new); return NULL; } new->fh = f->fh; new->flags = f->flags | MF_NOCLOSE; new->rleft = new->wleft = -1; return new; } void Fclose(mFILE *f) { Fflush(f); if (!(f->flags & MF_NOCLOSE)) Close(f->fh); free(f->buf); free(f); } size_t Fread(void *ptr, size_t elsize, size_t els, mFILE *f) { long size, n = 0; char *p = (char *)ptr; if (!(f->flags & MF_READ)) return 0; size = elsize * els; if (!size) return 0; if (f->wleft >= 0) { Write(f->fh, f->buf, f->bufsize - f->wleft); f->wleft = -1; } if (f->rleft <= 0) { f->rleft = Read(f->fh, f->buf, f->bufsize); f->rptr = f->buf; if (!f->rleft) return 0; } while (size > f->rleft) { bcopy(f->rptr, p, f->rleft); p += f->rleft; n += f->rleft; size -= f->rleft; f->rleft = Read(f->fh, f->buf, f->bufsize); f->rptr = f->buf; if (!f->rleft) return n / elsize; } bcopy(f->rptr, p, size); f->rleft -= size; f->rptr += size; return (n+size) / elsize; } size_t Fwrite(void *ptr, size_t elsize, size_t els, mFILE *f) { long size, n = 0, n2; char *p = (char *)ptr; if (!(f->flags & MF_WRITE)) return 0; size = elsize * els; if (!size) return 0; if (f->rleft >= 0) { Seek(f->fh, -f->rleft, OFFSET_CURRENT); f->rleft = -1; } if (f->wleft < 0) { f->wleft = f->bufsize; f->wptr = f->buf; } if (size < f->wleft) { bcopy(p, f->wptr, size); f->wptr += size; f->wleft -= size; return size / elsize; } if (!Write(f->fh, f->buf, f->bufsize - f->wleft)) return 0; while (size >= f->bufsize) { n2 = Write(f->fh, p, f->bufsize); if (n2 < f->bufsize) return (n+n2) / elsize; p += f->bufsize; n += f->bufsize; size -= f->bufsize; } bcopy(p, f->buf, size); f->wptr = f->buf + size; f->wleft = f->bufsize - size; return (n+size) / elsize; } int Fgetc(mFILE *f) { if (!(f->flags & MF_READ)) return EOF; if (f->wleft >= 0) { Write(f->fh, f->buf, f->bufsize - f->wleft); f->wleft = -1; } if (f->rleft <= 0) { f->rleft = Read(f->fh, f->buf, f->bufsize); f->rptr = f->buf; if (!f->rleft) return EOF; } --f->rleft; return *f->rptr++; } int Fputc(int c, mFILE *f) { char ch = c; if (!(f->flags & MF_WRITE)) return EOF; if (f->rleft >= 0) { Seek(f->fh, -f->rleft, OFFSET_CURRENT); f->rleft = -1; } if (!f->wleft) { if (!Write(f->fh, f->buf, f->bufsize)) return EOF; f->wptr = f->buf; f->wleft = f->bufsize; } else if (f->wleft < 0) { f->wleft = f->bufsize; f->wptr = f->buf; } *f->wptr++ = c; --f->wleft; return c; } char *Fgets(char *buf, size_t size, mFILE *f) { char *p = buf; int c = 0; if (size < 1) return NULL; /* This might seem wrong, but it isn't. We want to store the * terminating newline in the string (if there's room), so we don't * check for the newline until after we've stored it. */ while (size > 1 && c != '\n' && (c = Fgetc(f)) != EOF) { *p++ = c; --size; } *p = 0; if (c == EOF && p == buf) return NULL; return buf; } int Fputs(char *buf, mFILE *f) { if (Fwrite(buf, strlen(buf), 1, f) != 1) return -1; return 0; } void Fseek(mFILE *f, size_t where, int how) { if (!(f->flags & MF_SEEK)) return; Fflush(f); Seek(f->fh, where, how-1); } size_t Ftell(mFILE *f) { size_t pos = Seek(f->fh, 0, OFFSET_CURRENT); if (f->rleft > 0) pos -= f->rleft; if (f->wleft >= 0) pos += f->bufsize - f->wleft; return pos; } void Fflush(mFILE *f) { if (f->rleft >= 0) { Seek(f->fh, -f->rleft, OFFSET_CURRENT); f->rleft = -1; } if (f->wleft >= 0 && f->wleft < f->bufsize) { Write(f->fh, f->buf, f->bufsize - f->wleft); f->wleft = -1; } } /* Return buffer on success, NULL on failure */ char *Fname(char *buf, size_t len, mFILE *f) { if (NameFromFH(f->fh, buf, len)) return buf; return NULL; }