235 lines
4.3 KiB
C
235 lines
4.3 KiB
C
#
|
|
#include "../param.h"
|
|
#include "../systm.h"
|
|
#include "../user.h"
|
|
#include "../inode.h"
|
|
#include "../filsys.h"
|
|
#include "../conf.h"
|
|
#include "../buf.h"
|
|
|
|
/*
|
|
* Look up an inode by device,inumber.
|
|
* If it is in core (in the inode structure),
|
|
* honor the locking protocol.
|
|
* If it is not in core, read it in from the
|
|
* specified device.
|
|
* If the inode is mounted on, perform
|
|
* the indicated indirection.
|
|
* In all cases, a pointer to a locked
|
|
* inode structure is returned.
|
|
*
|
|
* printf warning: no inodes -- if the inode
|
|
* structure is full
|
|
* panic: no imt -- if the mounted file
|
|
* system is not in the mount table.
|
|
* "cannot happen"
|
|
*/
|
|
iget(dev, ino)
|
|
{
|
|
register struct inode *p;
|
|
register *ip2;
|
|
int *ip1;
|
|
register struct mount *ip;
|
|
|
|
loop:
|
|
ip = NULL;
|
|
for(p = &inode[0]; p < &inode[NINODE]; p++) {
|
|
if(dev==p->i_dev && ino==p->i_number) {
|
|
if((p->i_flag&ILOCK) != 0) {
|
|
p->i_flag =| IWANT;
|
|
sleep(p, PINOD);
|
|
goto loop;
|
|
}
|
|
if((p->i_flag&IMOUNT) != 0) {
|
|
for(ip = &mount[0]; ip < &mount[NMOUNT]; ip++)
|
|
if(ip->m_inodp == p) {
|
|
dev = ip->m_dev;
|
|
ino = ROOTINO;
|
|
goto loop;
|
|
}
|
|
panic("no imt");
|
|
}
|
|
p->i_count++;
|
|
p->i_flag =| ILOCK;
|
|
return(p);
|
|
}
|
|
if(ip==NULL && p->i_count==0)
|
|
ip = p;
|
|
}
|
|
if((p=ip) == NULL) {
|
|
printf("Inode table overflow\n");
|
|
u.u_error = ENFILE;
|
|
return(NULL);
|
|
}
|
|
p->i_dev = dev;
|
|
p->i_number = ino;
|
|
p->i_flag = ILOCK;
|
|
p->i_count++;
|
|
p->i_lastr = -1;
|
|
ip = bread(dev, ldiv(ino+31,16));
|
|
/*
|
|
* Check I/O errors
|
|
*/
|
|
if (ip->b_flags&B_ERROR) {
|
|
brelse(ip);
|
|
iput(p);
|
|
return(NULL);
|
|
}
|
|
ip1 = ip->b_addr + 32*lrem(ino+31, 16);
|
|
ip2 = &p->i_mode;
|
|
while(ip2 < &p->i_addr[8])
|
|
*ip2++ = *ip1++;
|
|
brelse(ip);
|
|
return(p);
|
|
}
|
|
|
|
/*
|
|
* Decrement reference count of
|
|
* an inode structure.
|
|
* On the last reference,
|
|
* write the inode out and if necessary,
|
|
* truncate and deallocate the file.
|
|
*/
|
|
iput(p)
|
|
struct inode *p;
|
|
{
|
|
register *rp;
|
|
|
|
rp = p;
|
|
if(rp->i_count == 1) {
|
|
rp->i_flag =| ILOCK;
|
|
if(rp->i_nlink <= 0) {
|
|
itrunc(rp);
|
|
rp->i_mode = 0;
|
|
ifree(rp->i_dev, rp->i_number);
|
|
}
|
|
iupdat(rp, time);
|
|
prele(rp);
|
|
rp->i_flag = 0;
|
|
rp->i_number = 0;
|
|
}
|
|
rp->i_count--;
|
|
prele(rp);
|
|
}
|
|
|
|
/*
|
|
* Check accessed and update flags on
|
|
* an inode structure.
|
|
* If either is on, update the inode
|
|
* with the corresponding dates
|
|
* set to the argument tm.
|
|
*/
|
|
iupdat(p, tm)
|
|
int *p;
|
|
int *tm;
|
|
{
|
|
register *ip1, *ip2, *rp;
|
|
int *bp, i;
|
|
|
|
rp = p;
|
|
if((rp->i_flag&(IUPD|IACC)) != 0) {
|
|
if(getfs(rp->i_dev)->s_ronly)
|
|
return;
|
|
i = rp->i_number+31;
|
|
bp = bread(rp->i_dev, ldiv(i,16));
|
|
ip1 = bp->b_addr + 32*lrem(i, 16);
|
|
ip2 = &rp->i_mode;
|
|
while(ip2 < &rp->i_addr[8])
|
|
*ip1++ = *ip2++;
|
|
if(rp->i_flag&IACC) {
|
|
*ip1++ = time[0];
|
|
*ip1++ = time[1];
|
|
} else
|
|
ip1 =+ 2;
|
|
if(rp->i_flag&IUPD) {
|
|
*ip1++ = *tm++;
|
|
*ip1++ = *tm;
|
|
}
|
|
bwrite(bp);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Free all the disk blocks associated
|
|
* with the specified inode structure.
|
|
* The blocks of the file are removed
|
|
* in reverse order. This FILO
|
|
* algorithm will tend to maintain
|
|
* a contiguous free list much longer
|
|
* than FIFO.
|
|
*/
|
|
itrunc(ip)
|
|
int *ip;
|
|
{
|
|
register *rp, *bp, *cp;
|
|
int *dp, *ep;
|
|
|
|
rp = ip;
|
|
if((rp->i_mode&(IFCHR&IFBLK)) != 0)
|
|
return;
|
|
for(ip = &rp->i_addr[7]; ip >= &rp->i_addr[0]; ip--)
|
|
if(*ip) {
|
|
if((rp->i_mode&ILARG) != 0) {
|
|
bp = bread(rp->i_dev, *ip);
|
|
for(cp = bp->b_addr+512; cp >= bp->b_addr; cp--)
|
|
if(*cp) {
|
|
if(ip == &rp->i_addr[7]) {
|
|
dp = bread(rp->i_dev, *cp);
|
|
for(ep = dp->b_addr+512; ep >= dp->b_addr; ep--)
|
|
if(*ep)
|
|
free(rp->i_dev, *ep);
|
|
brelse(dp);
|
|
}
|
|
free(rp->i_dev, *cp);
|
|
}
|
|
brelse(bp);
|
|
}
|
|
free(rp->i_dev, *ip);
|
|
*ip = 0;
|
|
}
|
|
rp->i_mode =& ~ILARG;
|
|
rp->i_size0 = 0;
|
|
rp->i_size1 = 0;
|
|
rp->i_flag =| IUPD;
|
|
}
|
|
|
|
/*
|
|
* Make a new file.
|
|
*/
|
|
maknode(mode)
|
|
{
|
|
register *ip;
|
|
|
|
ip = ialloc(u.u_pdir->i_dev);
|
|
if (ip==NULL)
|
|
return(NULL);
|
|
ip->i_flag =| IACC|IUPD;
|
|
ip->i_mode = mode|IALLOC;
|
|
ip->i_nlink = 1;
|
|
ip->i_uid = u.u_uid;
|
|
ip->i_gid = u.u_gid;
|
|
wdir(ip);
|
|
return(ip);
|
|
}
|
|
|
|
/*
|
|
* Write a directory entry with
|
|
* parameters left as side effects
|
|
* to a call to namei.
|
|
*/
|
|
wdir(ip)
|
|
int *ip;
|
|
{
|
|
register char *cp1, *cp2;
|
|
|
|
u.u_dent.u_ino = ip->i_number;
|
|
cp1 = &u.u_dent.u_name[0];
|
|
for(cp2 = &u.u_dbuf[0]; cp2 < &u.u_dbuf[DIRSIZ];)
|
|
*cp1++ = *cp2++;
|
|
u.u_count = DIRSIZ+2;
|
|
u.u_segflg = 1;
|
|
u.u_base = &u.u_dent;
|
|
writei(u.u_pdir);
|
|
iput(u.u_pdir);
|
|
}
|