|
|
researchv10 Norman
#include "sys/param.h"
#include "sys/systm.h"
#include "sys/inode.h"
#include "sys/user.h"
#include "sys/buf.h"
#include "sys/proc.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.
*/
daddr_t
bmap(ip, bn, rwflg)
register struct inode *ip;
daddr_t bn;
{
register daddr_t i;
struct buf *bp, *nbp;
int j, sh;
daddr_t prev;
daddr_t nb, *bap;
dev_t dev;
if(bn < 0) {
u.u_error = EFBIG;
return((daddr_t)0);
}
dev = ip->i_dev;
rablock = 0;
/*
* blocks 0..NADDR-4 are direct blocks
*/
if(bn < NADDR-3) {
i = bn;
nb = ip->i_un.i_addr[i];
if(nb == 0) {
prev = (i > 0? ip->i_un.i_addr[i-1]: 0);
if(rwflg==B_READ || (bp = alloc(ip, prev))==NULL)
return((daddr_t)-1);
nb = dbtofsb(dev, bp->b_blkno);
if ((ip->i_mode&IFMT) == IFDIR)
/*
* Write directory blocks synchronously
* so they never appear with garbage in
* them on the disk.
*/
bwrite(bp);
else
bdwrite(bp);
ip->i_un.i_addr[i] = nb;
ip->i_flag |= IUPD|ICHG;
}
if(i < NADDR-4)
rablock = ip->i_un.i_addr[i+1];
return(nb);
}
/*
* addresses NADDR-3, NADDR-2, and NADDR-1
* have single, double, triple indirect blocks.
* the first step is to determine
* how many levels of indirection.
*/
sh = 0;
nb = 1;
bn -= NADDR-3;
for(j=3; j>0; j--) {
sh += NSHIFT(dev);
nb <<= NSHIFT(dev);
if(bn < nb)
break;
bn -= nb;
}
if(j == 0) {
u.u_error = EFBIG;
return((daddr_t)0);
}
/*
* fetch the first indirect block
*/
nb = ip->i_un.i_addr[NADDR-j];
if(nb == 0) {
prev = ip->i_un.i_addr[NADDR-j-1];
if(rwflg==B_READ || (bp = alloc(ip, prev))==NULL)
return((daddr_t)-1);
nb = dbtofsb(dev, bp->b_blkno);
/*
* Write synchronously so that indirect blocks
* never point at garbage.
*/
bwrite(bp);
ip->i_un.i_addr[NADDR-j] = nb;
ip->i_flag |= IUPD|ICHG;
}
/*
* fetch through the indirect blocks
*/
for(; j<=3; j++) {
bp = bread(dev, nb);
if(bp->b_flags & B_ERROR) {
brelse(bp);
return((daddr_t)0);
}
bap = bp->b_un.b_daddr;
sh -= NSHIFT(dev);
i = (bn>>sh) & NMASK(dev);
nb = bap[i];
if(nb == 0) {
prev = (i>0? bap[i-1]: 0);
if(rwflg==B_READ || (nbp = alloc(ip, prev))==NULL) {
brelse(bp);
return((daddr_t)-1);
}
nb = dbtofsb(dev, nbp->b_blkno);
if (j < 3 || (ip->i_mode&IFMT) == IFDIR)
/*
* Write synchronously so indirect blocks
* never point at garbage and blocks
* in directories never contain garbage.
*/
bwrite(nbp);
else
bdwrite(nbp);
bap[i] = nb;
bdwrite(bp);
} else
brelse(bp);
}
/*
* calculate read-ahead.
*/
if(i < NINDIR(dev)-1)
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)
register c;
{
register id;
if((id = u.u_segflg) == SEGSYS)
*u.u_base = c;
else
if(id==SEGUINST?suibyte(u.u_base, c):subyte(u.u_base, c) < 0) {
u.u_error = EFAULT;
return(-1);
}
u.u_count--;
u.u_offset = Lladd(u.u_offset, 1);
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, id;
if(u.u_count == 0)
return(-1);
if((id = u.u_segflg) == SEGSYS)
c = *u.u_base;
else
if((c = id==SEGUDATA?fubyte(u.u_base):fuibyte(u.u_base)) < 0) {
u.u_error = EFAULT;
return(-1);
}
u.u_count--;
u.u_offset = Lladd(u.u_offset, 1);
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()
{
}
imin(a, b)
{
return (a < b ? a : b);
}
imax(a, b)
{
return (a > b ? a : b);
}
/*
* this should probably come out eventually
*/
struct proc *
pfind(pid)
register int pid;
{
register struct proc *p;
for (p = proc; p < procNPROC; p++)
if (p->p_stat && p->p_pid == pid)
return (p);
return (NULL);
}
strncmp(s1, s2, len)
register char *s1, *s2;
register len;
{
do {
if (*s1 != *s2++)
return(1);
if (*s1++ == '\0')
return(0);
} while (--len);
return(0);
}
strcpy(to, fr)
register char *to, *fr;
{
while (*to++ = *fr++)
;
}
/*
* long-long support
*/
#define M 0x80000000
unsigned
Lshift(ll, l)
llong_t ll;
long l;
{
return (ll.hi<<(32-l)) | (ll.lo>>l);
}
llong_t
ltoL(l)
long l;
{
llong_t t;
t.hi = 0;
t.lo = l;
return t;
}
llong_t
Lladd(ll, l)
llong_t ll;
long l;
{
llong_t t;
long cin;
t = ll;
t.lo += l;
cin = ll.lo^t.lo;
if (l>=0) {
if ((ll.lo&cin)&M)
t.hi++;
} else {
if ((~ll.lo&cin)&M)
t.hi--;
}
return t;
}
llong_t
Luadd(ll, u)
llong_t ll;
unsigned long u;
{
llong_t t;
long cin;
t = ll;
t.lo += u;
cin = ll.lo^t.lo;
if ((ll.lo&cin)&M)
t.hi++;
return t;
}
llong_t
LLadd(lla, llb)
llong_t lla, llb;
{
llong_t t;
t.hi = lla.hi+llb.hi;
t.lo = lla.lo+llb.lo;
if ((lla.lo&llb.lo | lla.lo&~t.lo | llb.lo&~t.lo)&M)
t.hi++;
return t;
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.