#include "fileutil.h" #include #include #include #include #include int __fp_open(FILE *fp, int fd, bool use_buffering) { /* We initialize fdpos to 0 even in append mode (7.19.3§1) */ fp->fd = fd; fp->fdpos = 0; /* We assume all files in the filesystem are non-interactive in order to conform to (7.19.5.3§7) TODO: Vhex might want something more elaborate here */ if(use_buffering && setvbuf(fp, NULL, _IOFBF, BUFSIZ)) return -1; return 0; } void __fp_close(FILE *fp, bool free_fp) { if(!fp) return; if(fp->fd >= 0) { fflush(fp); close(fp->fd); } if(fp->bufowned) free(fp->buf); if(free_fp) free(fp); } void __fp_remove_buffer(FILE *fp) { if(fp->bufowned) free(fp->buf); fp->buf = NULL; fp->bufowned = false; fp->bufsize = 0; } bool __fp_set_buffer(FILE *fp, void *buf, size_t size) { bool owned = false; if(!buf) { owned = true; buf = malloc(size); if(!buf) return false; } fp->buf = buf; fp->bufowned = owned; fp->bufsize = size; return true; } void __fp_buffer_mode_read(FILE *fp) { if(__fp_hasbuf_write(fp)) { fflush(fp); } if(fp->buf) fp->bufdir = __FILE_BUF_READ; } void __fp_buffer_mode_write(FILE *fp) { if(__fp_hasbuf_read(fp)) fflush(fp); if(fp->buf) fp->bufdir = __FILE_BUF_WRITE; } ssize_t __fp_buffered_read(FILE *fp, void *data, size_t request_size) { if(!fp->buf || __fp_hasbuf_write(fp)) return -1; int read_size = min((int)request_size, fp->bufread - fp->bufpos); if(read_size <= 0) return 0; memcpy(data, fp->buf + fp->bufpos, read_size); fp->bufpos += read_size; fp->bufungetc = max(fp->bufungetc - read_size, 0); /* Rewind the buffer if we read it fully */ if(fp->bufpos >= fp->bufread) { fp->bufread = 0; fp->bufpos = 0; /* Clear temporary ungetc() buffers of _IONBF streams */ if(fp->bufmode == _IONBF) __fp_remove_buffer(fp); } return read_size; } ssize_t __fp_read(FILE *fp, void *data, size_t size) { size_t read_ = 0; while(read_ < size) { ssize_t rc = read(fp->fd, data + read_, size - read_); if(rc < 0) { fp->error = 1; return EOF; } if(rc == 0) { fp->eof = 1; break; } fp->fdpos += rc; read_ += rc; } return read_; } ssize_t __fp_write(FILE *fp, void const *data, size_t size) { size_t written = 0; while(written < size) { ssize_t rc = write(fp->fd, data + written, size - written); if(rc < 0) { fp->error = 1; return EOF; } if(rc == 0) break; fp->fdpos += rc; written += rc; } return written; } int __fp_parse_mode(char const *mode, FILE *fp) { int base = 0; bool binary = false; bool update = false; for(int i = 0; mode[i]; i++) { if(mode[i] == 'r' || mode[i] == 'w' || mode[i] == 'a') { if(base) goto err; base = mode[i]; } else if(mode[i] == 'b') binary = true; else if(mode[i] == '+') update = true; } if(!base) goto err; if(fp) { fp->readable = (base == 'r' || update); fp->writable = (base == 'w' || base == 'a' || update); fp->append = (base == 'a'); fp->text = !binary; } if(base == 'r') return (update ? O_RDWR : O_RDONLY); if(base == 'w') return (update ? O_RDWR : O_WRONLY) | O_CREAT | O_TRUNC; if(base == 'a') return (update ? O_RDWR : O_WRONLY) | O_CREAT; /* Fallthrough */ err: errno = EINVAL; return -1; }