/***************************************************************************** * FILE: fs.c * * * * DESC: * * - file system functions * * - sys_close, sys_dup, sys_sup2, sys_lseek * * - msdos file operations * * * * Copyright (C) 1993,1994 * * Rainer Schnitker, Heeper Str. 283, 33607 Bielefeld * * email: rainer@mathematik.uni-bielefeld.de * * * *****************************************************************************/ #include #include #include "DPMI.H" #include "PROCESS.H" #include "DOSERRNO.H" #include "CDOSX32.H" #include "SIGNALS.H" #include "RMLIB.H" #include "PRINTF.H" #include "FS.H" #include "COPY32.H" #include "TERMIO.H" #define NIL_FP (struct file *)0 struct file rsx_filetab[RSX_NFILES]; /* ** make entries for standard dos_files */ void init_rsx_filetab() { rsx_filetab[0].f_mode = FMODE_READ; rsx_filetab[0].f_count = 1; rsx_filetab[0].f_doshandle = 0; rsx_filetab[0].f_op = & msdos_fop; rsx_filetab[1].f_mode = FMODE_WRITE; rsx_filetab[1].f_count = 1; rsx_filetab[1].f_doshandle = 1; rsx_filetab[1].f_op = & msdos_fop; rsx_filetab[2].f_mode = FMODE_WRITE; rsx_filetab[2].f_count = 1; rsx_filetab[2].f_doshandle = 2; rsx_filetab[2].f_op = & msdos_fop; rsx_filetab[3].f_mode = FMODE_WRITE; rsx_filetab[3].f_count = 1; rsx_filetab[3].f_doshandle = 3; rsx_filetab[3].f_op = & msdos_fop; rsx_filetab[4].f_mode = FMODE_WRITE; rsx_filetab[4].f_count = 1; rsx_filetab[4].f_doshandle = 4; rsx_filetab[4].f_op = & msdos_fop; } /* ** search for free file pointer */ int get_empty_proc_filp(void) { int fd, i; /* search for entry in proc tab */ for (fd = 0 ; fd < N_FILES ; fd++) if (!npz->filp[fd]) break; if (fd >= N_FILES) return -EMX_EMFILE; /* search for entry in rsx_filetab */ for (i = 0; i < RSX_NFILES; i++) if (! rsx_filetab[i].f_count) break; if (rsx_filetab[i].f_count) return -EMX_EMFILE; rsx_filetab[i].f_count = 1; rsx_filetab[i].f_mode = FMODE_READ | FMODE_WRITE; npz->filp[fd] = & rsx_filetab[i]; return fd; } /* ** convert handle to real DOS file handle */ int get_dos_handle(int handle) { if (handle >= N_FILES || !npz->filp[handle]) return -1; else if (npz->filp[handle]->f_doshandle == -1) return -2; else return npz->filp[handle]->f_doshandle; } /* ** close a file handle */ int sys_close(int fd) { struct file * filp; if (fd >= N_FILES) return -EMX_EBADF; if (!(filp = npz->filp[fd])) return -EMX_EBADF; npz->filp[fd] = NIL_FP; if (filp->f_count == 0) { printf("FS error: file %d count is 0\n", fd); return 0; } if (filp->f_count > 1) { filp->f_count--; return 0; } if (filp->f_op && filp->f_op->release) filp->f_op->release(filp); filp->f_count--; return 0; } /* ** dup a file handle */ static int dupfd(unsigned int fd, unsigned int arg) { if (fd >= N_FILES || !npz->filp[fd]) return -EMX_EBADF; if (arg >= N_FILES) return -EMX_EINVAL; while (arg < N_FILES) if (npz->filp[arg]) arg++; else break; if (arg >= N_FILES) return -EMX_EMFILE; npz->filp[arg] = npz->filp[fd]; npz->filp[arg]->f_count++; return arg; } int sys_dup2(unsigned int oldfd, unsigned int newfd) { if (oldfd >= N_FILES || !npz->filp[oldfd]) return -EMX_EBADF; if (newfd == oldfd) return newfd; if (newfd > N_FILES) return -EMX_EBADF; if (newfd == N_FILES) return -EMX_EBADF; sys_close(newfd); return dupfd(oldfd, newfd); } int sys_dup(unsigned int fildes) { return dupfd(fildes,0); } /* ** read from file handle */ ARGUSER sys_read(int fd, ARGUSER buf, ARGUSER bytes) { struct file * file; if (fd >= N_FILES) return -EMX_EBADF; if (!(file = npz->filp[fd])) return -EMX_EBADF; if (! file->f_op || ! file->f_op->read) return -EMX_EBADF; /* tested in cdosx32 ** if (verify_illegal(npz, buf, bytes)) { send_signal(npz, SIGSEGV); return -EMX_EINTR; } */ return file->f_op->read(file, buf, bytes); } /* ** write to file handle */ ARGUSER sys_write(int fd, ARGUSER buf, ARGUSER bytes) { struct file * file; if (fd >= N_FILES) return -EMX_EBADF; if (!(file = npz->filp[fd])) return -EMX_EBADF; if (! file->f_op || ! file->f_op->write) return -EMX_EBADF; /* tested in cdosx32 ** if (verify_illegal(npz, buf, bytes)) { send_signal(npz, SIGSEGV); return -EMX_EINTR; } */ return file->f_op->write(file, buf, bytes); } /* ** seek file handle */ long sys_lseek(int fd, long off, int orgin) { struct file * file; if (fd >= N_FILES) return -EMX_EBADF; if (!(file = npz->filp[fd])) return -EMX_EBADF; if (! file->f_op || ! file->f_op->lseek) return -EMX_EBADF; return file->f_op->lseek(file, off, orgin); } int sys_select(ARGUSER u_select) { DWORD time_val[2]; struct _select select; struct _fd_set fd_in, fd_out; struct file *file; int nhandles; int i; /* get select struct */ cpy32_16(DS, u_select, &select, sizeof(select)); if (select.time != 0) { /* get time struct */ cpy32_16(DS, select.time, time_val, sizeof(time_val)); time_val[0] = time_val[0] * 182 / 10; /* timer tics */ } else { time_val[0] = 0xffffffff; } if (select.readfds) /* get read fd struct */ cpy32_16(DS, select.readfds, &fd_in, sizeof(fd_in)); else return -EMX_EINVAL; memset( &fd_out, 0, sizeof(fd_out)); /* FD_ZERO */ if (select.nfds > 40) select.nfds = 40; nhandles = 0; for (i = 0; i < (int)select.nfds; i++) { if (!(FD_ISSET(i, &fd_in))) continue; file = npz->filp[i]; if (!(file = npz->filp[i])) continue; if (! file->f_op || ! file->f_op->select) continue; if (file->f_op->select(file, time_val[0])) { FD_SET(i, &fd_out); nhandles ++; } } if (select.readfds) /* put read fd struct */ cpy16_32(DS, select.readfds, &fd_out, sizeof(fd_out)); if (select.writefds) bzero32(DS, select.writefds, sizeof(struct _fd_set)); if (select.excepfds) bzero32(DS, select.excepfds, sizeof(struct _fd_set)); return nhandles; } int sys_ioctl(int fd, ARGUSER request, ARGUSER arg) { struct file * file; if (fd >= N_FILES) return -EMX_EBADF; if (!(file = npz->filp[fd])) return -EMX_EBADF; if (! file->f_op || ! file->f_op->ioctl) return -EMX_EBADF; return file->f_op->ioctl(file, request, arg); } int sys_pipe(ARGUSER size, ARGUSER arg) { #if 0 return -EMX_EMSDOS; #else int fin, fout; struct pipe_info *pi; struct file *file; fin = get_empty_proc_filp(); fout = get_empty_proc_filp(); if (fin < 0 || fout < 0) { npz->filp[fin]->f_count = 0; npz->filp[fout]->f_count = 0; return -EMX_EMFILE; } pi = (struct pipe_info *) malloc (sizeof(struct pipe_info)); if (!pi) { npz->filp[fin]->f_count = 0; npz->filp[fout]->f_count = 0; return -EMX_ENOMEM; } if (AllocMem(size, &(pi->memhandle), &(pi->memaddress))) { npz->filp[fin]->f_count = 0; npz->filp[fout]->f_count = 0; free(pi); return -EMX_ENOMEM; } AllocLDT(1, & pi->sel); SetBaseAddress(pi->sel, pi->memaddress); SetAccess(pi->sel, APP_DATA_SEL, 0); SetLimit(pi->sel, size-1); pi->pos = 0; pi->len = 0; pi->size = size; pi->rd_openers = 0; pi->wr_openers = 0; pi->readers = 1; pi->writers = 1; file = npz->filp[fin]; file->f_mode = FMODE_READ; file->f_doshandle = -1; file->f_op = & pipe_fop; file->f_offset = 0; file->f_info = (union file_info *) pi; file = npz->filp[fout]; file->f_mode = FMODE_WRITE; file->f_doshandle = -1; file->f_op = & pipe_fop; file->f_offset = 0; file->f_info = (union file_info *) pi; store32 (DS, arg, (long) fin); store32 (DS, arg + 4, (long) fout); return 0; #endif } /* ----------------------------------------------------------------- */ /* ** MS-DOS ** fileoperations */ static long msdos_lseek(struct file *filp, long off, int orgin) { long pos; if ((pos = rm_lseek(filp->f_doshandle, off, orgin)) == -1L) return -emx_errno; else return pos; } static ARGUSER msdos_read(struct file *filp, ARGUSER buf, ARGUSER bytes) { return cdosx_read(filp->f_doshandle, buf, bytes); } static ARGUSER msdos_write(struct file *filp, ARGUSER buf, ARGUSER bytes) { return cdosx_write(filp->f_doshandle, buf, bytes); } extern int sysemx_select(int handle, DWORD time); static int msdos_select(struct file *filp, DWORD time) { return sysemx_select(filp->f_doshandle, time); } extern int sysemx_ioctl(int handle, ARGUSER request, ARGUSER arg); static int msdos_ioctl(struct file *filp, ARGUSER request, ARGUSER arg) { return sysemx_ioctl(filp->f_doshandle, request, arg); } static void msdos_release(struct file *filp) { if (filp->f_doshandle <= 4) printf("FS error: closing doshandle %d\n", filp->f_doshandle); else rm_close(filp->f_doshandle); } struct file_operations msdos_fop = { msdos_lseek, msdos_read, msdos_write, msdos_select, msdos_ioctl, NULL, /* special open */ msdos_release }; /* ----------------------------------------------------------------- */ /* ** pipe !! JUST A FIRST TEST !! ** fileoperations */ #define PIPE_EMPTY(pipe) ((pipe)->len == 0) #define PIPE_FULL(pipe) ((pipe)->len == (pipe)->size) #define PIPE_FREE(pipe) ((pipe)->size - (pipe)->len) #define PIPE_END(pipe) (((pipe)->pos+(pipe)->len)&((pipe)->size-1)) #define PIPE_MAX_READ(pipe) ((pipe)->size - (pipe)->pos) #define PIPE_MAX_WRITE(pipe) ((pipe)->size - PIPE_END(pipe)) static long pipe_lseek(struct file *filp, long off, int orgin) { emx_errno = EMX_ESPIPE; return -1; } static ARGUSER pipe_read(struct file *filp, ARGUSER buf, ARGUSER bytes) { struct pipe_info *pi = (struct pipe_info *) filp->f_info; long chars, size, read = 0; if (filp->f_flags & FCNTL_NDELAY) { if (PIPE_EMPTY(pi)) if (pi->writers) return -EMX_EAGAIN; else return 0; } while (PIPE_EMPTY(pi)) { if (!pi->writers) return 0; if (!schedule()) /* no other processes */ return -EMX_EPIPE; } while (bytes > 0 && (size = pi->len)) { chars = PIPE_MAX_READ(pi); if (chars > bytes) chars = bytes; if (chars > size) chars = size; cpy32_32(pi->sel, pi->pos, DS, buf, chars); pi->len -= chars; pi->pos += chars; pi->pos &= (pi->size-1); buf += chars; bytes -= chars; read += chars; } if (read) return read; if (pi->writers) return -EMX_EAGAIN; return 0; } static ARGUSER pipe_write(struct file *filp, ARGUSER buf, ARGUSER bytes) { struct pipe_info *pi = (struct pipe_info *) filp->f_info; long chars, free, written = 0; if (!pi->readers) { send_signal(npz, SIGPIPE); return -EMX_EPIPE; } if (bytes <= pi->size) free = bytes; else free = 1; while (bytes > 0) { while (PIPE_FREE(pi) < free) { /* not enough space */ if (!pi->readers) { send_signal(npz, SIGPIPE); return written ? written : -EMX_EPIPE; } if (filp->f_flags & FCNTL_NDELAY) return written ? written : -EMX_EAGAIN; if (!schedule()) return -EMX_EPIPE; } while (bytes > 0 && (free = PIPE_FREE(pi))) { chars = PIPE_MAX_WRITE(pi); if (chars > bytes) chars = bytes; if (chars > free) chars = free; cpy32_32(DS, buf, pi->sel, PIPE_END(pi), chars); pi->len += chars; written += chars; bytes -= chars; buf += chars; } if (!schedule()) return -EMX_EPIPE; } return written; } static int pipe_select(struct file *filp, DWORD time) { struct pipe_info *pi = (struct pipe_info *) filp->f_info; if (filp->f_mode == FMODE_READ) return (pi->len != 0L); else if (filp->f_mode == FMODE_WRITE) return (pi->len != pi->size); else return 0; } static int pipe_ioctl(struct file *filp, ARGUSER request, ARGUSER arg) { long temp; struct pipe_info *pi = (struct pipe_info *) filp->f_info; if (request == FIONREAD) temp = pi->len; else if (request == FGETHTYPE) temp = HT_UPIPE; else return -EMX_EINVAL; store32(DS, arg, temp); return 0; } static void pipe_release(struct file *filp) { struct pipe_info *pi = (struct pipe_info *) filp->f_info; if (filp->f_mode & FMODE_READ) pi->readers--; else if (filp->f_mode & FMODE_WRITE) pi->writers--; else puts("FS error: pipe with no r/w mode"); if (!pi->readers && !pi->writers) { FreeMem(pi->memhandle); free(pi); filp->f_info = NULL; } } struct file_operations pipe_fop = { pipe_lseek, pipe_read, pipe_write, pipe_select, pipe_ioctl, NULL, /* special open */ pipe_release };