Interdata_v6/usr/sys/subr.c
#
/*
*/
#include "param.h"
#include "conf.h"
#include "inode.h"
#include "user.h"
#include "buf.h"
#include "systm.h"
/*
* Bmap defines the structure of file system storage
* by returning the physical block number on a device given the
* inode and the logical block number in a file.
* When convenient, it also leaves the physical
* block number of the next block of the file in rablock
* for use in read-ahead.
*/
bmap(ip, bn)
struct inode *ip;
int bn;
{
register *bp, *bap, nb;
int *nbp, d, i;
d = ip->i_dev;
if(bn & ~0377777) { /***/
u.u_error = EFBIG;
return(0);
}
if((ip->i_mode&ILARG) == 0) {
/*
* small file algorithm
*/
if((bn & ~7) != 0) {
/*
* convert small to large
*/
if ((bp = alloc(d)) == NULL)
return(NULL);
bap = bp->b_addr;
for(i=0; i<8; i++) {
*bap++ = ip->i_addr[i];
ip->i_addr[i] = 0;
}
ip->i_addr[0] = bp->b_blkno;
bdwrite(bp);
ip->i_mode =| ILARG;
goto large;
}
nb = ip->i_addr[bn];
if(nb == 0 && (bp = alloc(d)) != NULL) {
bdwrite(bp);
nb = bp->b_blkno;
ip->i_addr[bn] = nb;
ip->i_flag =| IUPD;
}
rablock = 0;
if (bn<7)
rablock = ip->i_addr[bn+1];
return(nb);
}
/*
* large file algorithm
*/
large:
i = bn>>7; /***/
if(i > 7) /***/
i = 7;
if((nb=ip->i_addr[i]) == 0) {
ip->i_flag =| IUPD;
if ((bp = alloc(d)) == NULL)
return(NULL);
ip->i_addr[i] = bp->b_blkno;
} else
bp = bread(d, nb);
bap = bp->b_addr;
/*
* "huge" fetch of double indirect block
*/
if(i == 7) {
i = ((bn>>7)&0177) - 7; /***/
if((nb=bap[i]) == 0) {
if((nbp = alloc(d)) == NULL) {
brelse(bp);
return(NULL);
}
bap[i] = nbp->b_blkno;
bdwrite(bp);
} else {
brelse(bp);
nbp = bread(d, nb);
}
bp = nbp;
bap = bp->b_addr;
}
/*
* normal indirect fetch
*/
i = bn & 0177; /***/
if((nb=bap[i]) == 0 && (nbp = alloc(d)) != NULL) {
nb = nbp->b_blkno;
bap[i] = nb;
bdwrite(nbp);
bdwrite(bp);
} else
brelse(bp);
rablock = 0;
if(i < 127) /***/
rablock = bap[i+1];
return(nb);
}
/*
* Pass back c to the user at his location u_base;
* update u_base, u_count, and u_offset. Return -1
* on the last character of the user's read.
* u_base is in the user address space unless u_segflg is set.
*/
passc(c)
{
if(u.u_segflg)
*u.u_base = c; else
if(subyte(u.u_base, c) < 0) {
u.u_error = EFAULT;
return(-1);
}
u.u_count--;
if(++u.u_offset[1] == 0)
u.u_offset[0]++;
u.u_base++;
return(u.u_count == 0? -1: 0);
}
/*
* Pick up and return the next character from the user's
* write call at location u_base;
* update u_base, u_count, and u_offset. Return -1
* when u_count is exhausted. u_base is in the user's
* address space unless u_segflg is set.
*/
cpass()
{
register c;
if(u.u_count == 0)
return(-1);
if(u.u_segflg)
c = *u.u_base; else
if((c=fubyte(u.u_base)) < 0) {
u.u_error = EFAULT;
return(-1);
}
u.u_count--;
if(++u.u_offset[1] == 0)
u.u_offset[0]++;
u.u_base++;
return(c&0377);
}
/*
* Routine which sets a user error; placed in
* illegal entries in the bdevsw and cdevsw tables.
*/
nodev()
{
u.u_error = ENODEV;
}
/*
* Null routine; placed in insignificant entries
* in the bdevsw and cdevsw tables.
*/
nulldev()
{
}
/*
* copy count words from from to to.
*/
bcopy(from, to, count)
int *from, *to;
{
register *a, *b, c;
a = from;
b = to;
c = count;
do
*b++ = *a++;
while(--c);
}