home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Crawly Crypt Collection 2
/
crawlyvol2.bin
/
alt_os
/
mint
/
mfs6011
/
source
/
minixfs
/
zone.c
< prev
Wrap
C/C++ Source or Header
|
1994-12-30
|
19KB
|
725 lines
/* This file is part of 'minixfs' Copyright 1991,1992,1993 S.N. Henson */
#include "minixfs.h"
#include "proto.h"
#include "global.h"
int read_zone(num,buf,drive,control)
long num ;
void *buf;
int drive;
cache_control *control;
{
if(num) bcopy(cget_block(num,drive,control),buf,(size_t)BLOCK_SIZE);
else bzero(buf,(size_t)BLOCK_SIZE);
return(0);
}
/* Only ever used for directories so always syscache */
bufr *get_zone(num,drive)
long num ;
int drive;
{
return(cget_block(num,drive,&syscache));
}
/* Zone cache stuff (same as cache stuff but with checking) */
cache *cget_zone(num,drive,control,guess)
long num;
int drive;
cache_control *control;
cache **guess;
{
return (cache_get(num,drive,control,guess));
}
cache *cput_zone(num,drive,control)
long num;
int drive;
cache_control *control;
{
return (cache_put(num,drive,control));
}
int write_zone(num,buf,drive,control)
long num ;
void *buf;
int drive;
cache_control *control;
{
cput_block(num,drive,buf,control);
return(0);
}
/* This is a 'clever' write_zone which recognises consecutive blocks and
* queues requests until it gets one out of sequence.This allows large
* i/o requests to be done with a single Rwabs for consecutive blocks
* which is much faster than lots of little ones.
*/
int write_zones(num,buf,drive,control)
long num;
void *buf;
int drive;
cache_control *control;
{
static void *qstart,*qnext;
static long nstart,nnext,count;
static short qdrive=-1;
cache *p;
int i;
if(drive != -1 && (p=in_cache(num,drive,control,NOGUESS)) )
{
bcopy(buf,p->buffer,(size_t)BLOCK_SIZE);
p->status=1;
}
if(buf!=qnext || nnext!=num || qdrive!=drive || count > MAX_RWS )
{
/* Flush out queue */
if(qdrive!=-1)
{
chk_zone(nstart,count,drive);
if(count<8) for(i=0;i<count;i++)
write_zone(nstart+i,qstart+(i<<L_BS),qdrive,control);
else crwabs(3,qstart,count,nstart,qdrive);
}
qdrive=drive;
qstart=buf;
qnext=buf+BLOCK_SIZE;
nstart=num;
nnext=num+1;
count=1;
}
else
{
qnext+=BLOCK_SIZE;
count++;
nnext++;
}
return 0;
}
/* This is an equivalent for read ... but this is a bit harder as it is
* not obvious what to do with the cache . What we finally do is to
* always get data from the cache if we can , though this could easily
* turn a large consecutive i/o request into lots of little ones . The
* cache is not filled from the new read unless we are only reading
* 1 zone ... basically this assumes that if the user reads several zones
* then the program will be doing doing some sort of cacheing itself .
*/
int read_zones(num,buf,drive,control)
long num;
void *buf;
int drive;
cache_control *control;
{
static void *qstart,*qnext;
static long nstart,nnext,count;
static short qdrive=-1;
cache *p;
/* Read from cache if necessary */
if(drive != -1 && (p=in_cache(num,drive,control,NOGUESS)) )
{
bcopy(p->buffer,buf,(size_t)BLOCK_SIZE);
drive=-1; /* Force flush of queued entries */
}
if( qdrive!=drive || buf!=qnext || nnext!=num || (count > MAX_RWS) )
{
/* Flush out queue */
if(qdrive!=-1)
{
if(count==1) read_zone(nstart,qstart,qdrive,control);
else {
if(nnext) crwabs(2,qstart,count,nstart,qdrive);
else bzero(qstart,count*(size_t)BLOCK_SIZE);
}
}
qdrive=drive;
qstart=buf;
qnext=buf;
nstart=num;
nnext=num;
count=0;
}
if(qdrive!=-1)
{
qnext+=BLOCK_SIZE;
count++;
if(nnext)nnext++;
}
return 0;
}
/* This routine finds the zone 'numr' of an inode , traversing indirect
* and double indirect zones as required if flag!=0 zones are added as
* required . Having two filesystem versions makes this a bit trickier, in
* fact although using a single routine looks more elegant it is slow,
* so two versions are used.
*/
/* Special case for l_write:
if flag > 1, and a new zone is allocated, prepare a cleared block.
This is for writing to sparse files, when only a partial block is
written, the rest must be cleared. Since directories are never
sparse, always use usrcache in this case. */
long find_zone(rip,numr,drive,flag)
d_inode *rip;
long numr;
int drive;
int flag;
{
super_info *psblk=super_ptr[drive];
return psblk->version ? find_zone2(rip,numr,drive,flag,&dummy) :
find_zone1(rip,numr,drive,flag);
}
long find_zone11(rip,numr,drive,flag,fch)
d_inode1 *rip;
long numr;
int drive;
int flag;
f_cache *fch;
{
long temp_zone;
unshort *zptr,*zptr2;
cache *tmp,*tmp2;
/* Past EOF ? */
if(!flag && (numr*BLOCK_SIZE >= rip->i_size) ) return(0);
/* Zone in inode ? */
if(numr < NR_DZONE_NUM)
{
temp_zone=rip->i_zone[numr];
if(temp_zone || !flag ) return temp_zone;
temp_zone = (rip->i_zone[numr]=alloc_zone(drive));
goto new_zone;
}
numr-=NR_DZONE_NUM;
/* In indirect zone then ? */
if(numr < NR_INDIRECTS)
{
if(rip->i_zone[7])
{
tmp=
cget_zone(rip->i_zone[7],drive,&syscache,&fch->izguess);
zptr=&tmp->buffer->bind1[numr];
if( *zptr || !flag )return *zptr;
if( (*zptr=alloc_zone(drive)) ) tmp->status=2;
temp_zone = *zptr;
goto new_zone;
}
else
{
if(!flag || !(rip->i_zone[7]=alloc_zone(drive))) return 0;
tmp=cput_zone(rip->i_zone[7],drive,&syscache);
fch->izguess=tmp;
bzero(tmp->buffer,(size_t)BLOCK_SIZE);
temp_zone = tmp->buffer->bind1[numr]=alloc_zone(drive);
goto new_zone;
}
}
/* Erk double indirect .... */
numr-=NR_INDIRECTS;
if (numr < NR_INDIRECTS * NR_INDIRECTS)
{
if(rip->i_zone[8]) {
tmp2=cget_zone(rip->i_zone[8],drive,&syscache,&fch->dizguess);
zptr2=&tmp2->buffer->bind1[numr>>LNR_IND];
if(*zptr2)
{
tmp=cget_zone(*zptr2,drive,&syscache,&fch->izguess);
zptr=&tmp->buffer->bind1[numr & (NR_INDIRECTS-1)];
if(*zptr || !flag)return *zptr;
if( (*zptr=alloc_zone(drive)) ) tmp->status=2;
temp_zone = *zptr;
goto new_zone;
}
else
{
if(!flag ||!(*zptr2=alloc_zone(drive)) )return 0;
tmp2->status=2;
tmp=cput_zone(*zptr2,drive,&syscache);
fch->izguess=tmp;
bzero(tmp->buffer,(size_t)BLOCK_SIZE);
zptr=&tmp->buffer->bind1[numr & (NR_INDIRECTS-1)];
temp_zone = *zptr=alloc_zone(drive);
goto new_zone;
}
}
if(!flag || !(rip->i_zone[8]=alloc_zone(drive)) ) return 0;
tmp2=cput_zone(rip->i_zone[8],drive,&syscache);
fch->dizguess=tmp2;
bzero(tmp2->buffer,(size_t)BLOCK_SIZE);
zptr2=&tmp2->buffer->bind1[numr>>LNR_IND];
if(!(*zptr2=alloc_zone(drive))) return 0;
tmp=cput_zone(*zptr2,drive,&syscache);
fch->izguess=tmp;
bzero(tmp->buffer,(size_t)BLOCK_SIZE);
zptr=&tmp->buffer->bind1[numr & (NR_INDIRECTS-1)];
temp_zone = *zptr=alloc_zone(drive) ;
goto new_zone;
}
return 0;
new_zone:
if (temp_zone && flag > 1)
{
tmp = cput_zone (temp_zone, drive, &usrcache);
bzero (tmp->buffer, (size_t) BLOCK_SIZE);
}
return temp_zone;
}
long find_zone1(rip,numr,drive,flag)
d_inode *rip;
long numr;
int drive;
int flag;
{
long temp_zone;
unshort *zptr,*zptr2;
cache *tmp,*tmp2;
/* Past EOF ? */
if(!flag && (numr*BLOCK_SIZE >= rip->i_size) ) return(0);
/* Zone in inode ? */
if(numr < NR_DZONE_NUM)
{
temp_zone=rip->i_zone[numr];
if(temp_zone || !flag ) return temp_zone;
return(rip->i_zone[numr]=alloc_zone(drive));
}
numr-=NR_DZONE_NUM;
/* In indirect zone then ? */
if(numr < NR_INDIRECTS)
{
if(rip->i_zone[7])
{
tmp=cget_zone(rip->i_zone[7],drive,&syscache,NOGUESS);
zptr=&tmp->buffer->bind1[numr];
if( *zptr || !flag )return *zptr;
if( (*zptr=alloc_zone(drive)) ) tmp->status=2;
return *zptr;
}
else
{
if(!flag || !(rip->i_zone[7]=alloc_zone(drive))) return 0;
tmp=cput_zone(rip->i_zone[7],drive,&syscache);
bzero(tmp->buffer,(size_t)BLOCK_SIZE);
return tmp->buffer->bind1[numr]=alloc_zone(drive);
}
}
/* Erk double indirect .... */
numr-=NR_INDIRECTS;
if (numr < NR_INDIRECTS * NR_INDIRECTS)
{
if(rip->i_zone[8]) {
tmp2=cget_zone(rip->i_zone[8],drive,&syscache,NOGUESS);
zptr2=&tmp2->buffer->bind1[numr>>LNR_IND];
if(*zptr2)
{
tmp=cget_zone(*zptr2,drive,&syscache,NOGUESS);
zptr=&tmp->buffer->bind1[numr & (NR_INDIRECTS-1)];
if(*zptr || !flag)return *zptr;
if( (*zptr=alloc_zone(drive)) ) tmp->status=2;
return *zptr;
}
else
{
if(!flag ||!(*zptr2=alloc_zone(drive)) )return 0;
tmp2->status=2;
tmp=cput_zone(*zptr2,drive,&syscache);
bzero(tmp->buffer,(size_t)BLOCK_SIZE);
zptr=&tmp->buffer->bind1[numr & (NR_INDIRECTS-1)];
return *zptr=alloc_zone(drive);
}
}
if(!flag || !(rip->i_zone[8]=alloc_zone(drive)) ) return 0;
tmp2=cput_zone(rip->i_zone[8],drive,&syscache);
bzero(tmp2->buffer,(size_t)BLOCK_SIZE);
zptr2=&tmp2->buffer->bind1[numr>>LNR_IND];
if(!(*zptr2=alloc_zone(drive))) return 0;
tmp=cput_zone(*zptr2,drive,&syscache);
bzero(tmp->buffer,(size_t)BLOCK_SIZE);
zptr=&tmp->buffer->bind1[numr & (NR_INDIRECTS-1)];
return *zptr=alloc_zone(drive) ;
}
return 0;
}
long find_zone2(rip,numr,drive,flag,fch)
d_inode *rip;
long numr;
int drive;
int flag;
f_cache *fch;
{
long temp_zone;
long *zptr,*zptr2;
cache *tmp,*tmp2;
/* Past EOF ? */
if((numr*BLOCK_SIZE >= rip->i_size) && !flag ) return(0);
/* Zone in inode ? */
if(numr < NR_DZONE_NUM2)
{
temp_zone=rip->i_zone[numr];
if(temp_zone || !flag ) return temp_zone;
temp_zone = (rip->i_zone[numr]=alloc_zone(drive));
goto new_zone;
}
numr-=NR_DZONE_NUM2;
/* In indirect zone then ? */
if(numr < NR_INDIRECTS2)
{
if(rip->i_zone[7])
{
tmp=
cget_zone(rip->i_zone[7],drive,&syscache,&fch->izguess);
zptr=&tmp->buffer->bind[numr];
if( *zptr || !flag )return *zptr;
if( (*zptr=alloc_zone(drive)) ) tmp->status=2;
temp_zone = *zptr;
goto new_zone;
}
else
{
if(!flag || !(rip->i_zone[7]=alloc_zone(drive))) return 0;
tmp=cput_zone(rip->i_zone[7],drive,&syscache);
bzero(tmp->buffer,(size_t)BLOCK_SIZE);
temp_zone = tmp->buffer->bind[numr]=alloc_zone(drive);
goto new_zone;
}
}
/* Erk double indirect .... */
numr-=NR_INDIRECTS2;
if (numr < NR_INDIRECTS2 * NR_INDIRECTS2)
{
if(rip->i_zone[8]) {
tmp2=cget_zone(rip->i_zone[8],drive,&syscache,&fch->dizguess);
zptr2=&tmp2->buffer->bind[numr>>LNR_IND2];
if(*zptr2)
{
tmp=
cget_zone(*zptr2,drive,&syscache,&fch->izguess);
zptr=&tmp->buffer->bind[numr & (NR_INDIRECTS2-1)];
if(*zptr || !flag)return *zptr;
if( (*zptr=alloc_zone(drive)) ) tmp->status=2;
temp_zone = *zptr;
goto new_zone;
}
else
{
if(!flag ||!(*zptr2=alloc_zone(drive)) )return 0;
tmp2->status=2;
tmp=cput_zone(*zptr2,drive,&syscache);
bzero(tmp->buffer,(size_t)BLOCK_SIZE);
zptr=&tmp->buffer->bind[numr & (NR_INDIRECTS2-1)];
temp_zone = *zptr=alloc_zone(drive);
goto new_zone;
}
}
if(!flag || !(rip->i_zone[8]=alloc_zone(drive)) ) return 0;
tmp2=cput_zone(rip->i_zone[8],drive,&syscache);
bzero(tmp2->buffer,(size_t)BLOCK_SIZE);
zptr2=&tmp2->buffer->bind[numr>>LNR_IND2];
if(!(*zptr2=alloc_zone(drive))) return 0;
tmp=cput_zone(*zptr2,drive,&syscache);
bzero(tmp->buffer,(size_t)BLOCK_SIZE);
zptr=&tmp->buffer->bind[numr & (NR_INDIRECTS2-1)];
temp_zone = *zptr=alloc_zone(drive) ;
goto new_zone;
}
/* Triple indirect */
numr -= NR_INDIRECTS2 * NR_INDIRECTS2;
if (numr < NR_INDIRECTS2 * NR_INDIRECTS2 * NR_INDIRECTS2)
{
long *zptr3;
cache *tmp3;
if (rip->i_zone[9])
{
tmp3 = cget_zone (rip->i_zone[9], drive, &syscache, NOGUESS);
zptr3 = &tmp3->buffer->bind[numr >> (LNR_IND2 * 2)];
if (*zptr3)
{
tmp2 = cget_zone (*zptr3, drive, &syscache,
&fch->dizguess);
zptr2 = &tmp2->buffer->bind[(numr >> LNR_IND2)
& (NR_INDIRECTS2 - 1)];
if (*zptr2)
{
tmp = cget_zone (*zptr2, drive, &syscache,
&fch->izguess);
zptr = &tmp->buffer->bind[numr & (NR_INDIRECTS2-1)];
if (*zptr || !flag)
return *zptr;
if ((*zptr = alloc_zone (drive)) != 0)
tmp->status = 2;
temp_zone = *zptr;
goto new_zone;
}
else
{
if (!flag || !(*zptr2 = alloc_zone (drive)))
return 0;
tmp2->status = 2;
tmp = cput_zone (*zptr2, drive, &syscache);
bzero (tmp->buffer, (size_t) BLOCK_SIZE);
zptr = &tmp->buffer->bind[numr & (NR_INDIRECTS2 - 1)];
temp_zone = *zptr = alloc_zone (drive);
goto new_zone;
}
}
else
{
if (!flag || !(*zptr3 = alloc_zone (drive)))
return 0;
tmp3->status = 2;
tmp2 = cput_zone (*zptr3, drive, &syscache);
bzero (tmp2->buffer, (size_t) BLOCK_SIZE);
zptr2 = &tmp2->buffer->bind[(numr >> LNR_IND2)
& (NR_INDIRECTS2 - 1)];
if (!(*zptr2 = alloc_zone (drive)))
return 0;
tmp = cput_zone (*zptr2, drive, &syscache);
bzero (tmp->buffer, (size_t) BLOCK_SIZE);
zptr = &tmp->buffer->bind[numr & (NR_INDIRECTS2 - 1)];
temp_zone = *zptr = alloc_zone (drive);
goto new_zone;
}
}
if (!flag || !(rip->i_zone[9] = alloc_zone (drive)))
return 0;
tmp3 = cput_zone (rip->i_zone[9], drive, &syscache);
bzero (tmp3->buffer, (size_t) BLOCK_SIZE);
zptr3 = &tmp3->buffer->bind[numr >> (LNR_IND2 * 2)];
if (!(*zptr3 = alloc_zone (drive)))
return 0;
tmp2 = cput_zone (*zptr3, drive, &syscache);
bzero (tmp2->buffer, (size_t) BLOCK_SIZE);
zptr2 = &tmp2->buffer->bind[(numr >> LNR_IND2)
& (NR_INDIRECTS2 - 1)];
if (!(*zptr2 = alloc_zone (drive)))
return 0;
tmp = cput_zone (*zptr2, drive, &syscache);
bzero (tmp->buffer, (size_t) BLOCK_SIZE);
zptr = &tmp->buffer->bind[numr & (NR_INDIRECTS2 - 1)];
temp_zone = *zptr = alloc_zone (drive);
goto new_zone;
}
return 0;
new_zone:
if (temp_zone && flag > 1)
{
#if 1
cache_control *control = &usrcache;
if (IS_DIR((*rip))) {
ALERT("find_zone: Drive %d sparse dir!",drive);
control = &syscache;
}
tmp = cput_zone (temp_zone, drive, control);
#else
tmp = cput_zone (temp_zone, drive, &usrcache);
#endif
bzero (tmp->buffer, (size_t) BLOCK_SIZE);
}
return temp_zone;
}
/* This reads zone number 'numr' of an inode .
* It returns the actual number of valid characters in 'numr' , this is only
* used for directories so it is hard-coded for the system cache.
*/
int next_zone(rip,numr,buf,drive)
d_inode *rip;
long numr;
void *buf;
int drive;
{
long ztemp;
long ret;
ret=min(rip->i_size-numr*BLOCK_SIZE,BLOCK_SIZE);
if(ret <= 0)return 0;
ztemp=find_zone(rip,numr,drive,0);
read_zone(ztemp,buf,drive,&syscache);
return (int)ret;
}
/* As above but reads in cache pointer */
int cnext_zone(rip,numr,buf,drive)
d_inode *rip;
long numr;
cache **buf;
int drive;
{
long ztemp;
long ret;
ret=min(rip->i_size-numr*BLOCK_SIZE,BLOCK_SIZE);
if(ret <= 0)return 0;
ztemp=find_zone(rip,numr,drive,0);
*buf=cget_zone(ztemp,drive,&syscache,NOGUESS);
return (int)ret;
}
/* l_write is used internally for doing things a normal user cannot such
* as writing to a directory ... it accepts 5 parameters , an inode num
* a position (current position of write) a count which is the number of
* characters to write,a buffer and a drive , it updates i_size as needed
* and allocates zones as required , it is nastier than a read because it
* has to write partial blocks within valid blocks and to write beyond EOF
*/
long l_write(inum,pos,len,buf,drive)
unsigned inum;
long pos;
long len;
const void *buf;
int drive;
{
return super_ptr[drive]->version ? l_write2(inum,pos,len,buf,drive) :
l_write1(inum,pos,len,buf,drive);
}
long l_write1(inum,pos,len,buf,drive)
unsigned inum;
long pos;
long len;
const void *buf;
int drive;
{
register const void *p = buf; /* Current position in buffer */
d_inode1 *rip;
long chunk;
long left=len;
long zne;
cache_control *control;
int *status;
rip=get_inode1(inum,drive,&status,NOGUESS);
/* Work out which cache to use */
control = (IS_DIR((*rip))||IS_SYM((*rip))) ? &syscache : &usrcache;
if(pos==-1l) pos=rip->i_size; /* If pos==-1 append */
chunk=pos/BLOCK_SIZE;
while(left) /* Loop while characters remain to be written */
{
long zoff;
ushort wleft;
cache *cp;
zoff = pos & (BLOCK_SIZE -1); /* Current zone position */
wleft=min(BLOCK_SIZE-zoff,left); /*Left to write in curr blk*/
zne = find_zone11 (rip, chunk++, drive,
1 + (zoff || pos < rip->i_size),
&dummy); /* Current zone in file */
if(zne==0) break; /* Partition full */
if((zoff) || ( (left < BLOCK_SIZE) && (pos+left<rip->i_size)))
{
cp=cget_zone(zne,drive,control,NOGUESS);
cp->status=2;
}
else
{
cp=cput_zone(zne,drive,control);
if(wleft!=BLOCK_SIZE)bzero(cp->buffer->bdata,(size_t)BLOCK_SIZE);
}
bcopy(p,&cp->buffer->bdata[zoff],(size_t)wleft);
pos+=wleft;
p+=wleft;
if(pos>rip->i_size)rip->i_size=pos;
left-=wleft;
}
rip->i_mtime=Unixtime(Timestamp(), Datestamp());
*status=2;
return(len-left);
}
long l_write2(inum,pos,len,buf,drive)
unsigned inum;
long pos;
long len;
const void *buf;
int drive;
{
register const void *p = buf; /* Current position in buffer */
d_inode *rip;
long chunk;
long left=len;
long zne;
cache_control *control;
int *status;
rip=get_inode2(inum,drive,&status,NOGUESS);
/* Work out which cache to use */
control = (IS_DIR((*rip))||IS_SYM((*rip))) ? &syscache : &usrcache;
if(pos==-1l) pos=rip->i_size; /* If pos==-1 append */
chunk=pos/BLOCK_SIZE;
while(left) /* Loop while characters remain to be written */
{
long zoff;
ushort wleft;
cache *cp;
zoff = pos & (BLOCK_SIZE -1); /* Current zone position */
wleft=min(BLOCK_SIZE-zoff,left); /*Left to write in curr blk*/
if((zoff) || ( (left < BLOCK_SIZE) && (pos+left<rip->i_size)))
{
zne = find_zone2 (rip, chunk++, drive, 2,
&dummy); /* Current zone in file */
if(zne==0)break; /* Partition full */
cp=cget_zone(zne,drive,control,NOGUESS);
cp->status=2;
}
else
{
zne = find_zone2 (rip, chunk++, drive, 1,
&dummy); /* Current zone in file */
if(zne==0)break; /* Partition full */
cp=cput_zone(zne,drive,control);
if(wleft!=BLOCK_SIZE)bzero(cp->buffer->bdata,(size_t)BLOCK_SIZE);
}
bcopy(p,&cp->buffer->bdata[zoff],(size_t)wleft);
pos+=wleft;
p+=wleft;
if(pos>rip->i_size)rip->i_size=pos;
left-=wleft;
}
rip->i_mtime=Unixtime(Timestamp(), Datestamp());
*status=2;
return(len-left);
}