2.9BSD/usr/net/sys/sys/rdwri.c
/*
* SCCS id @(#)rdwri.c 2.1 (Berkeley) 8/5/83
*/
#include "param.h"
#include <sys/systm.h>
#include <sys/inode.h>
#include <sys/dir.h>
#include <sys/user.h>
#include <sys/buf.h>
#include <sys/conf.h>
/*
* 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);
}