#include "fs.h" #include "buf.h" #include "inode.h" #include #include /*===========================================================================* * fs_readwrite * *===========================================================================*/ int fs_readwrite(message *fs_m_in, message *fs_m_out) { int r, rw_flag; struct buf *bp; cp_grant_id_t gid; off_t position, f_size; unsigned int nrbytes, cum_io; pmode_t mode_word; struct inode *rip; pino_t inumb; r = OK; cum_io = 0; inumb = (pino_t) fs_m_in->REQ_INODE_NR; /* Find the inode referred */ if ((rip = find_inode(inumb)) == NULL) return(EINVAL); mode_word = rip->i_mode & I_TYPE; if (mode_word != I_NAMED_PIPE) return(EIO); f_size = rip->i_size; /* Get the values from the request message */ rw_flag = (fs_m_in->m_type == REQ_READ ? READING : WRITING); gid = (cp_grant_id_t) fs_m_in->REQ_GRANT; nrbytes = (unsigned) fs_m_in->REQ_NBYTES; /* We can't read beyond the max file position */ if (nrbytes > PIPE_BUF) return(EFBIG); /* Mark inode in use */ if ((get_inode(rip->i_dev, rip->i_num)) == NULL) return(err_code); if ((bp = get_block(rip->i_dev, rip->i_num)) == NULL) return(err_code); if (rw_flag == WRITING) { /* Check in advance to see if file will grow too big. */ /* Casting nrbytes to signed is safe, because it's guaranteed not to * be beyond max signed value (i.e., MAX_FILE_POS). */ position = rip->i_size; if ((unsigned) position + nrbytes > PIPE_BUF) { put_inode(rip); put_block(rip->i_dev, rip->i_num); return(EFBIG); } } else { position = 0; if (nrbytes > rip->i_size) { /* There aren't that many bytes to read */ nrbytes = rip->i_size; } } if (rw_flag == READING) { /* Copy a chunk from the block buffer to user space. */ r = sys_safecopyto(fs_m_in->m_source, gid, (vir_bytes) 0, (vir_bytes) (bp->b_data+position), (size_t) nrbytes); } else { /* Copy a chunk from user space to the block buffer. */ r = sys_safecopyfrom(fs_m_in->m_source, gid, (vir_bytes) 0, (vir_bytes) (bp->b_data+position), (size_t) nrbytes); } if (r == OK) { position += (signed) nrbytes; /* Update position */ cum_io += nrbytes; } /* On write, update file size and access time. */ if (rw_flag == WRITING) { rip->i_size = position; } else { memmove(bp->b_data, bp->b_data+nrbytes, rip->i_size - nrbytes); rip->i_size -= nrbytes; } if (rw_flag == READING) rip->i_update |= ATIME; if (rw_flag == WRITING) rip->i_update |= CTIME | MTIME; fs_m_out->RES_NBYTES = (size_t) cum_io; fs_m_out->RES_SEEK_POS = rip->i_size; put_inode(rip); put_block(rip->i_dev, rip->i_num); return(r); }