/* * SCCS id @(#)rdwri.c 2.1 (Berkeley) 8/5/83 */ #include "param.h" #include #include #include #include #include #include /* * Read the file corresponding to * the inode pointed at by the argument. * The actual read arguments are found * in the variables: * u_base core address for destination * u_offset byte offset in file * u_count number of bytes to read * u_segflg read to kernel/user/user I */ readi(ip) register struct inode *ip; { struct buf *bp; dev_t dev; daddr_t lbn, bn; off_t diff; register on, n; int type; if(u.u_count == 0) return; if(u.u_offset < 0) { u.u_error = EINVAL; return; } ip->i_flag |= IACC; dev = (dev_t)ip->i_un.i_rdev; type = ip->i_mode&IFMT; #ifdef MPX_FILS if (type==IFCHR || type==IFMPC) #else if (type==IFCHR) #endif return((*cdevsw[major(dev)].d_read)(dev)); do { lbn = bn = u.u_offset >> BSHIFT; on = u.u_offset & BMASK; n = MIN((unsigned)(BSIZE-on), u.u_count); #ifdef MPX_FILS if (type!=IFBLK && type!=IFMPB) #else if (type!=IFBLK) #endif { diff = ip->i_size - u.u_offset; if(diff <= 0) return; if(diff < n) n = diff; bn = bmap(ip, bn, B_READ); if(u.u_error) return; dev = ip->i_dev; } else rablock = bn+1; if ((long)bn<0) { bp = geteblk(); clrbuf(bp); } else if (ip->i_un.i_lastr+1==lbn) bp = breada(dev, bn, rablock); else bp = bread(dev, bn); ip->i_un.i_lastr = lbn; n = MIN((unsigned)n, BSIZE-bp->b_resid); if (n!=0) { iomove(mapin(bp)+on, n, B_READ); mapout(bp); } if (n+on==BSIZE || u.u_offset==ip->i_size) { if (ip->i_flag & IPIPE) bp->b_flags &= ~B_DELWRI; /* cancel i/o */ bp->b_flags |= B_AGE; } brelse(bp); } while(u.u_error==0 && u.u_count!=0 && n>0); } /* * Write the file corresponding to * the inode pointed at by the argument. * The actual write arguments are found * in the variables: * u_base core address for source * u_offset byte offset in file * u_count number of bytes to write * u_segflg write to kernel/user/user I */ writei(ip) register struct inode *ip; { struct buf *bp; dev_t dev; daddr_t bn; register n, on; register type; #ifdef UCB_FSFIX struct direct *dp; #endif #ifndef INSECURE /* * clear set-uid/gid on any write */ ip->i_mode &= ~(ISUID|ISGID); #endif if(u.u_offset < 0) { u.u_error = EINVAL; return; } dev = (dev_t)ip->i_un.i_rdev; type = ip->i_mode&IFMT; #ifdef MPX_FILS if (type==IFCHR || type==IFMPC) #else if (type==IFCHR) #endif { ip->i_flag |= IUPD|ICHG; (*cdevsw[major(dev)].d_write)(dev); return; } if (u.u_count == 0) return; do { bn = u.u_offset >> BSHIFT; on = u.u_offset & BMASK; n = MIN((unsigned)(BSIZE-on), u.u_count); #ifdef MPX_FILS if (type!=IFBLK && type!=IFMPB) #else if (type!=IFBLK) #endif { #ifdef UCB_QUOTAS if ((bn = bmap(ip, bn, B_WRITE)) == 0) return; #else bn = bmap(ip, bn, B_WRITE); #endif if (bn < 0) return; dev = ip->i_dev; } if (n == BSIZE) bp = getblk(dev, bn); else { bp = bread(dev, bn); /* * Tape drivers don't clear buffers on end-of-tape * any longer (clrbuf can't be called from interrupt). */ if (bp->b_resid == BSIZE) clrbuf(bp); } #ifdef UCB_FSFIX iomove((dp = (struct direct *)((unsigned)mapin(bp)+on)), n, B_WRITE); #else iomove(mapin(bp)+on, n, B_WRITE); mapout(bp); #endif if(u.u_error != 0) { #ifdef UCB_FSFIX mapout(bp); #endif brelse(bp); } else { #ifdef UCB_FSFIX if ((ip->i_mode&IFMT) == IFDIR && (dp->d_ino == 0)) { mapout(bp); /* * Writing to clear a directory entry. * Must insure the write occurs before * the inode is freed, or may end up * pointing at a new (different) file * if inode is quickly allocated again * and system crashes. */ bwrite(bp); } else { mapout(bp); if (((u.u_offset & BMASK) == 0) && (ip->i_flag & IPIPE) == 0) { bp->b_flags |= B_AGE; bawrite(bp); } else bdwrite(bp); } #else UCB_FSFIX if (((u.u_offset & BMASK) == 0) && (ip->i_flag & IPIPE) == 0) bp->b_flags |= B_AGE; bdwrite(bp); #endif UCB_FSFIX } #ifndef UCB_SYMLINKS if (u.u_offset > ip->i_size && (type == IFDIR || type == IFREG)) #else if (u.u_offset > ip->i_size && (type == IFDIR || type == IFREG || type == IFLNK)) #endif ip->i_size = u.u_offset; ip->i_flag |= IUPD|ICHG; } while(u.u_error == 0 && u.u_count != 0); } /* * Move n bytes at byte location cp * to/from (flag) the user/kernel (u.segflg) * area starting at u.base. * Update all the arguments by the number * of bytes moved. * * There are 2 algorithms, * if source address, dest address and count * are all even in a user copy, * then the machine language copyin/copyout * is called. * If not, its done byte by byte with * cpass and passc. */ iomove(cp, n, flag) register caddr_t cp; register n; { register t; if (n == 0) return; if(u.u_segflg != 1 && ((n | (int)cp | (int)u.u_base) & (NBPW-1)) == 0) { if (flag == B_WRITE) if (u.u_segflg == 0) t = copyin(u.u_base, (caddr_t)cp, n); else t = copyiin(u.u_base, (caddr_t)cp, n); else if (u.u_segflg == 0) t = copyout((caddr_t)cp, u.u_base, n); else t = copyiout((caddr_t)cp, u.u_base, n); if (t) { u.u_error = EFAULT; return; } u.u_base += n; u.u_offset += n; u.u_count -= n; return; } if (flag == B_WRITE) { do { if ((t = cpass()) < 0) return; *cp++ = t; } while (--n); } else do { if(passc(*cp++) < 0) return; } while (--n); }